home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 January: Mac OS SDK / Dev.CD Jan 99 SDK2.toast / Development Kits / USBDDK_v1.0.1_updated / Examples / PrinterClassDriver / PrinterClassDriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-29  |  93.7 KB  |  2,904 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        PrinterClassDriver.c
  3.  
  4.     Contains:    MacOS USB printer class driver
  5.                 [ref. IEEE Std 1284-1994]
  6.  
  7.     Version:    xxx put version here xxx
  8.  
  9. */
  10.  
  11.  
  12. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  13.     includes
  14.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  15. #include <Devices.h>
  16. #include <DriverServices.h>
  17. #include <Interrupts.h>
  18. #include <LowMem.h>
  19. #include <Folders.h>
  20. #include <String.h>
  21. #include <stdio.h>
  22. #include <USB.h>
  23.  
  24. #ifndef __CODEFRAGMENTS__
  25. #include <codefragments.h>
  26. #endif
  27.  
  28. #include "PrinterClassDriver.h"
  29. #include "TradDriverLoaderLib.h"
  30.  
  31. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  32.     constants
  33.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  34. #define MAX_SUFFIX                    127        // maximum copies we'll enter in unit table
  35. #define kUSBParallelDrvrRsrcID    12
  36. #define kMinDrvrUnitNumber            48            // minimum unit table entry which we'll install
  37. #define kUSS720MillisecondDelay    3*1000    // poll every three seconds
  38. #define kUSS720StatusMSDelay        10            // poll one hundred times per second
  39. #define MAX_USB_TRANSFER_SIZE        TRANSFER_SIZE            // zero acts as manifest for conditional compilation
  40.  
  41. #define kUSBAttributeBulk            0x02
  42. #define kUSBInputEndpointMask        0x80
  43.  
  44. enum
  45. {
  46.     kCString = 0,                // StateStr, USBStatusStr selector
  47.     kPString,                    // StateStr, USBStatusStr selector
  48.     kDrvrFirstDigit = 5        // length_byte + ".USB" = 5
  49. };
  50. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  51.     manifest constants
  52. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  53. //
  54. //    DEBUGGING                        extra debugging information to USB Expert Log
  55. //    DOUBLE_BUFFER                    use a page aligned buffer in system heap to double buffer app i/o
  56. //    LOG                                echo all the write data to a log file in the system folder
  57. // LOCK_MEMORY                        LockMemory on the i/o buffer before write and unlock on write completion
  58. // VIRTUAL_MEMORY_CHECK            check the physical addresses of the buffer we pass for write requests
  59. // MACSBUG_ON_READ                break into MacsBug before each read request
  60. //    MACSBUG_ON_READ_COMPLETE    break into MacsBug at each read completion routine
  61. //    MACSBUG_ON_WRITE                break into MacsBug on each write request
  62. // MACSBUG_ON_WRITE_COMPLETE    break into MacsBug at each write completion routine
  63. //
  64. #define DEBUGGING                            0    /* DEBUGGING */
  65. #define DOUBLE_BUFFER                    1    /* DOUBLE_BUFFER */
  66. #define LOG                                    0    /* LOG */
  67. #define LOCK_MEMORY                        1    /* LOCK_MEMORY */
  68. #define MACSBUG_ON_READ                    0    /* MACSBUG_ON_READ */
  69. #define MACSBUG_ON_READ_COMPLETE        0    /* MACSBUG_ON_READ_COMPLETE */ 
  70. #define MACSBUG_ON_WRITE                0    /* MACSBUG_ON_WRITE */
  71. #define MACSBUG_ON_WRITE_COMPLETE    0    /* MACSBUG_ON_WRITE_COMPLETE */ 
  72. #define VIRTUAL_MEMORY_CHECK            0    /* VIRTUAL_MEMORY_CHECK require LOCK_MEMORY, currently broken */
  73.  
  74. #if LOG
  75. #define LOGGING(x)    x
  76. #include <stdio.h>
  77. #else
  78. #define LOGGING(x)
  79. #endif
  80.  
  81. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  82.     globals
  83.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  84. static struct usbPrinterPBStruct    printerClassRecord;
  85. static FSSpec                            printerClassDriverFileSpec;
  86. LOGGING( static FILE                    *logfile );
  87. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  88.     prototypes
  89.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  90.  
  91. static void    PrinterDeviceCompletionProc(USBPB *pb);
  92. static void SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb );
  93. static        USBEndPointDescriptor *FindEndpoint( USBInterfaceDescriptor *pInterface, int endpointType );
  94. static void    SoftReset( USBPB *usbprint, short interfaceNum );
  95. static void    CapabilityRequest( USBPB *pb, Ptr p, long length, short config, short interfaceNum, short alternateSetting );
  96. static void    CentronicsStatus( USBPB *usbprint, Ptr p, short interfaceNum );
  97. static void CompletionProc(USBPB *pb);
  98. static int    cstrlen( char *p );
  99. static void    cstrcpy( char *dst, char *src );
  100. static void    cstrcat( char *dst, char *src );
  101.  
  102. void            PrinterDeviceInitiateTransaction(USBPB *pb);
  103.  
  104. OSErr            CFMInitialization( CFragInitBlock *initBlock );
  105.  
  106. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  107.     Name:        HexString8
  108.  
  109.     Input Parameters:    
  110.         v                unsigned long value
  111.         
  112.     Output Parameters:
  113.         p                8 bytes: hex string representing value
  114.         
  115.     Description:
  116.  
  117.     Change History:
  118.         28 Feb 1998,    oja:        Original version.
  119. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  120. static void
  121. HexString8( unsigned long v, unsigned char *p )
  122. {
  123.     int    shift;
  124.     
  125.     for ( shift = 32-4; shift >= 0; shift -= 4 )
  126.     {
  127.         char c = (v >> shift) & 0x0F;
  128.         *p++ = c + (c > 9? ('A'-10): '0');
  129.     }
  130. }
  131.  
  132. #if DEBUG
  133. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  134.     Name:        hexstr
  135.  
  136.     Input Parameters:    
  137.         count                number of bytes
  138.         p                    pointer to bytes
  139.         
  140.     Output Parameters:
  141.         q                    hex dump of data
  142.         
  143.     Description:
  144.  
  145.     Change History:
  146.         28 Jul 1998,    oja:        Original version.
  147. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  148. void
  149. hexstr( int count, char *p, char *q );
  150.  
  151. void
  152. hexstr( int count, char *p, char *q )
  153. {
  154.     char *s = p;
  155.     int i = count;
  156.     for ( ; count > 0; --count, ++p )
  157.     {
  158.         int hi, lo;
  159.         hi = (*p >> 4)& 0x0F;
  160.         lo = *p & 0x0F;
  161.         *q++ = '0';
  162.         *q++ = 'x';
  163.         *q++ = hi + (hi > 9? 'A' - 10: '0');
  164.         *q++ = lo + (lo > 9? 'A' - 10: '0');
  165.         *q++ = ' ';
  166.     }
  167.     for ( ; i > 0; --i, ++s )
  168.         *q++ = *s < ' ' || *s > 0x7E? '.': *s;
  169. }
  170. #endif
  171.  
  172. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  173.     Name:        cstrlen
  174.  
  175.     Input Parameters:    
  176.         p            pointer to c-string
  177.         
  178.     Output Parameters:
  179.         int        length of string
  180.  
  181.     Description:
  182.         A replacement for strlen, since we don't want to depend on the
  183.         c library (can cause vm double page faults)
  184.  
  185.     Change History:
  186.         17 Aug 1998,    oja:        Original version.
  187. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  188.  
  189. static int
  190. cstrlen( char *p )
  191. {
  192.     int result = 0;
  193.     
  194.     while ( *p++ != '\0' )
  195.         ++result;
  196.  
  197.     return result;
  198. }
  199.  
  200. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  201.     Name:        cstrcpy
  202.  
  203.     Input Parameters:    
  204.         src        pointer to source c-string
  205.         
  206.     Output Parameters:
  207.         dst        c-string copy of src string
  208.  
  209.     Description:
  210.         A replacement for strcpy, since we don't want to depend on the
  211.         c library (can cause vm double page faults)
  212.  
  213.     Change History:
  214.         17 Aug 1998,    oja:        Original version.
  215. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  216.  
  217. static void
  218. cstrcpy( char *dst, char *src )
  219. {
  220.     while ( (*dst++ = *src++) != 0 )
  221.         ;
  222. }
  223.  
  224. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  225.     Name:        cstrcat
  226.  
  227.     Input Parameters:    
  228.         src        pointer to source c-string
  229.         
  230.     Output Parameters:
  231.         dst        c-string copy of src string
  232.  
  233.     Description:
  234.         A replacement for strcpy, since we don't want to depend on the
  235.         c library (can cause vm double page faults)
  236.  
  237.     Change History:
  238.         17 Aug 1998,    oja:        Original version.
  239. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  240.  
  241. static void
  242. cstrcat( char *dst, char *src )
  243. {
  244.     dst += cstrlen( dst );        // skip to end of the existing string
  245.     while ( (*dst++ = *src++) != 0 )
  246.         ;
  247. }
  248.  
  249. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  250.     Name:        USBStatusStr
  251.  
  252.     Input Parameters:    
  253.         usbStatus            usb error code
  254.         kind                    kPString or kCString
  255.         
  256.     Output Parameters:
  257.         unsigned char *    description of error (c-string or p-string)
  258.  
  259.     Description:
  260.         a simple mapping of errors to human-readable form
  261.  
  262.     Change History:
  263.         24 Apr 1998,    oja:        param to HexString8 was off-by-one
  264.         26 Mar 1998,    oja:        added kStrPrintClass to catenated strings
  265.         28 Feb 1998,    oja:        Original version.
  266. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  267. static unsigned char *
  268. USBStatusStr( OSStatus usbStatus, int kind )
  269. {
  270.     unsigned char *p;
  271.  
  272.     switch ( usbStatus )
  273.     {
  274.         case    kUSBInternalErr:                    p = "\p" kStrPrinterClass "Internal error"; break;
  275.         case    kUSBUnknownDeviceErr:            p = "\p" kStrPrinterClass "Unknown device"; break;
  276.         case    kUSBUnknownPipeErr:                 p = "\p" kStrPrinterClass "Unknown pipe"; break;
  277.         case    kUSBTooManyPipesErr:                p = "\p" kStrPrinterClass "Too many pipes"; break;
  278.         case    kUSBIncorrectTypeErr:            p = "\p" kStrPrinterClass "Incorrect type"; break;
  279.         case    kUSBRqErr:                            p = "\p" kStrPrinterClass "Request error"; break;
  280.         case    kUSBUnknownRequestErr:            p = "\p" kStrPrinterClass "Unknown request"; break;
  281.         case    kUSBTooManyTransactionsErr:    p = "\p" kStrPrinterClass "Too many transactions"; break;
  282.         case    kUSBAlreadyOpenErr:                p = "\p" kStrPrinterClass "Already open"; break;
  283.         case    kUSBNoDeviceErr:                    p = "\p" kStrPrinterClass "No device"; break;
  284.         case    kUSBDeviceErr:                        p = "\p" kStrPrinterClass "Device error"; break;
  285.         case    kUSBOutOfMemoryErr:                p = "\p" kStrPrinterClass "Out of memory"; break;
  286.         case    kUSBNotFound:                        p = "\p" kStrPrinterClass "Not found"; break;
  287.         case    kUSBLinkErr:                        p = "\p" kStrPrinterClass "Link Err"; break;
  288.         case    kUSBCRCErr:                            p = "\p" kStrPrinterClass "Comms/Device err, bad CRC";  break;        
  289.         case    kUSBBitstufErr:                    p = "\p" kStrPrinterClass "Comms/Device err, bitstuffing"; break;        
  290.         case    kUSBDataToggleErr:                p = "\p" kStrPrinterClass "Comms/Device err, Bad data toggle"; break;        
  291.         case    kUSBEndpointStallErr:            p = "\p" kStrPrinterClass "Device didn't understand"; break;        
  292.         case    kUSBNotRespondingErr:            p = "\p" kStrPrinterClass "No device, device hung"; break;        
  293.         case    kUSBPIDCheckErr:                    p = "\p" kStrPrinterClass "Comms/Device err, PID CRC error"; break;        
  294.         case    kUSBWrongPIDErr:                    p = "\p" kStrPrinterClass "Comms/Device err, Bad or wrong PID"; break;        
  295.         case    kUSBOverRunErr:                    p = "\p" kStrPrinterClass "Packet too large or more data than buffer"; break;        
  296.         case    kUSBUnderRunErr:                    p = "\p" kStrPrinterClass "Less data than buffer"; break;        
  297.         case    kUSBRes1Err:                        p = "\p" kStrPrinterClass "kUSBRes1Err"; break;        
  298.         case    kUSBRes2Err:                        p = "\p" kStrPrinterClass "kUSBRes1Err"; break;        
  299.         case    kUSBBufOvrRunErr:                    p = "\p" kStrPrinterClass "Buffer over run error"; break;        
  300.         case    kUSBBufUnderRunErr:                p = "\p" kStrPrinterClass "Buffer under run error"; break;        
  301.         case    kUSBNotSent1Err:                    p = "\p" kStrPrinterClass "Transaction not sent1"; break;        
  302.         case    kUSBNotSent2Err:                    p = "\p" kStrPrinterClass "Transaction not sent2"; break;    
  303.         default:
  304.             p = "\p" kStrPrinterClass "Unknown error nnnnnnnn";
  305.             HexString8( usbStatus, p + *p - 8 + 1 );
  306.             break;
  307.     }
  308.     
  309.     return kind == kPString? p: p + 1;
  310. }
  311.  
  312. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  313.     Name:        StateStr
  314.  
  315.     Input Parameters:    
  316.         usbRefCon            usb error code
  317.         kind                    kPString or kCString
  318.         
  319.     Output Parameters:
  320.         unsigned char *    description of state (c-string or p-string)
  321.  
  322.     Description:
  323.         a simple mapping of states to human-readable form
  324.  
  325.     Change History:
  326.         24 Apr 1998,    oja:        param to HexString8 was off-by-one
  327.         26 Mar 1998,    oja:        added kStrPrintClass to catenated strings
  328.         28 Feb 1998,    oja:        Original version.
  329. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  330. static unsigned char *
  331. StateStr( OSStatus refCon, int kind )
  332. {
  333.     unsigned char *p;
  334.  
  335.     refCon &= ~(kTransactionPending | kRetryTransaction | kAsyncTransaction | kReturnFromDriver);
  336.     switch ( refCon )
  337.     {
  338.         case kGetConfigurationDescriptor:        p = "\p" kStrPrinterClass "kGetConfigurationDescriptor"; break;
  339.         case kGetFullConfiguration:                p = "\p" kStrPrinterClass "kGetFullConfiguration"; break;
  340.         case kSetInterface:                            p = "\p" kStrPrinterClass "kSetInterface"; break;
  341.         case kGetCapabilityString:                    p = "\p" kStrPrinterClass "kGetCapabilityString"; break;
  342.         case kDelayGetCapability:                    p = "\p" kStrPrinterClass "kDelayGetCapability"; break;
  343.         case kGetFullCapabilityString:            p = "\p" kStrPrinterClass "kGetFullCapabilityString"; break;
  344.         case kGetInterface:                            p = "\p" kStrPrinterClass "kGetInterface"; break;
  345.         case kOpenBulkOutPipe:                        p = "\p" kStrPrinterClass "kOpenBulkOutPipe"; break;
  346.         case kOpenBulkInPipe:                        p = "\p" kStrPrinterClass "kOpenBulkInPipe"; break;
  347.         case kEnterNameRegistry:                    p = "\p" kStrPrinterClass "kEnterNameRegistry"; break;
  348.         default:
  349.             p = "\p" kStrPrinterClass "Unknown state nnnnnnnn";
  350.             HexString8( refCon, p + *p - 8 + 1 );
  351.             break;
  352.     }
  353.     return kind == kPString? p: p + 1;    
  354. }
  355.  
  356. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  357.     Name:        HiHex
  358.  
  359.     Input Parameters:    
  360.         v                        only low byte used
  361.         
  362.     Output Parameters:
  363.         <function result>    high nibble represented as ASCII char
  364.         
  365.     Description:
  366.  
  367.     Change History:
  368.         20 Mar 1998,    oja:        Original version.
  369. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  370. static unsigned char
  371. HiHex( int v )
  372. {
  373.     unsigned char    hinibble = (v >> 4) & 0x0f;
  374.     return hinibble + ((hinibble > 9)? ('A'-10): '0');
  375. }
  376.  
  377. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  378.     Name:        LoHex
  379.  
  380.     Input Parameters:    
  381.         v                        only low byte used
  382.         
  383.     Output Parameters:
  384.         <function result>    low nibble represented as ASCII char
  385.         
  386.     Description:
  387.  
  388.     Change History:
  389.         20 Mar 1998,    oja:        Original version.
  390. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  391. static unsigned char
  392. LoHex( int v )
  393. {
  394.     unsigned char    lonibble = v & 0x0f;
  395.     return lonibble + ((lonibble > 9)? ('A'-10): '0');
  396. }
  397.  
  398. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  399.     Name:        immediateError
  400.  
  401.     Input Parameters:    
  402.         
  403.     Output Parameters:
  404.         
  405.     Description:
  406.  
  407.     Change History:
  408.         28 Feb 1998,    oja:        Original version.
  409. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  410. static Boolean
  411. immediateError(OSStatus err)
  412. {
  413.     return((err != kUSBPending) && (err != noErr) );
  414. }
  415.  
  416. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  417.     Name:        SetNullUSBParamBlock
  418.  
  419.     Input Parameters:    
  420.         pb                    pointer to USB parameter block
  421.         dev                USB device reference
  422.     Output Parameters:
  423.         pb                    all fields set to default values
  424.  
  425.     Description:
  426.         setup a USB parameter block for use by the current device
  427.  
  428.     Change History:
  429.          8 Jun 1998,    oja:        modified for new param blocks
  430.         28 Feb 1998,    oja:        Original version.
  431. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  432. static void
  433. SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb )
  434. {
  435.     pb->qlink = NULL;
  436.     pb->qType = 0;
  437.     pb->pbLength = sizeof(USBPB);
  438.     pb->pbVersion = kUSBCurrentPBVersion;
  439.     pb->usbFlags = 0;
  440.     pb->usbStatus = noErr;
  441.     pb->usbCompletion = (USBCompletion) NULL;
  442.  
  443.     pb->usbReference = dev;
  444. }
  445.  
  446.  
  447. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  448.     Name:        CountInterface
  449.  
  450.     Input Parameters:    
  451.         pConfigDesc            pointer to USB device configuration string
  452.         intClass                USB class id
  453.         intSubClass            USB subclass id
  454.     
  455.     Output Parameters:
  456.         <function result>    number of interfaces which match the criteria
  457.     
  458.     Description:
  459.         Count the number of interfaces (and alternates) which match the
  460.         desired class and subclass.
  461.  
  462.     Change History:
  463.         26 Mar 1998,    oja:        use USBToHostWord to access length of
  464.                                         Configuration Descriptor
  465.         28 Feb 1998,    oja:        Original version.
  466. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  467. static int
  468. CountInterface(
  469.     USBConfigurationDescriptorPtr pConfigDesc,
  470.     int intClass,
  471.     int intSubClass
  472. )
  473. {
  474.     //
  475.     //    find an interface (and alternateSetting) which allows the desired class, subclass and protocol
  476.     //
  477.     int                                numInterfaces;
  478.     UInt32                            totalLength;
  479.     void                                *pEndOfDescriptors;
  480.     USBInterfaceDescriptorPtr    pMyIntDesc;
  481.     USBDescriptorHeaderPtr        pCurrentDesc;
  482.     Ptr                                p;
  483.     
  484.     totalLength = USBToHostWord( ((USBConfigurationDescriptorPtr)pConfigDesc)->totalLength );
  485.     pEndOfDescriptors = (Ptr)pConfigDesc + totalLength;                // get the total length and add it to the start of the config space
  486.     pCurrentDesc = (USBDescriptorHeaderPtr)pConfigDesc;                // point the currentdesc to the start of the config space
  487.     
  488.     numInterfaces = 0;
  489.     while (pCurrentDesc < pEndOfDescriptors)                        // as long as we haven't exhausted all the descriptors
  490.     {
  491.         if (pCurrentDesc->descriptorType == kUSBInterfaceDesc)    // look at the current descriptor
  492.         {
  493.             pMyIntDesc = (USBInterfaceDescriptorPtr)pCurrentDesc;    // if it's an interface descriptor
  494.             if (pMyIntDesc->interfaceClass == intClass &&
  495.                     pMyIntDesc->interfaceSubClass == intSubClass )        // see if it's the request descriptor
  496.             {
  497.                 ++numInterfaces;
  498.             }
  499.         }
  500.         if ( pCurrentDesc->length == 0 )
  501.         {
  502.             IF_DEBUG( DebugStr( "\pCountInterfaces NULL" ) );
  503.             break;
  504.         }
  505.         p = (Ptr)pCurrentDesc + pCurrentDesc->length;
  506.         pCurrentDesc = (USBDescriptorHeaderPtr) p;                    // Nope, that either wasn't an interface descriptor
  507.     }                                                            // or it was, but not the droid we're looking for.
  508.     return numInterfaces;
  509. }
  510.  
  511.  
  512. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  513.     Name:        FindInterface
  514.  
  515.     Input Parameters:
  516.         pPrinterPB
  517.         protocol                                (USB specification) protocol constant
  518.         
  519.     Output Parameters:
  520.         pPrinterPB->pb.usbBuffer        pointer to the interface
  521.         pPrinterPB->pb.usbReqCount        offset to the interface
  522.  
  523.     Description:
  524.         Synchronous.
  525.  
  526.         find a print interface (and alternateSetting) which allows 
  527.         the desired protocol
  528.         
  529.         Note although USBFindNextInterfaceDescriptor returns immediately
  530.         it still requires a completion routine.
  531.  
  532.     Change History:
  533.         28 Feb 1998,    oja:        Original version.
  534. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  535. static struct USBInterfaceDescriptor *
  536. FindInterface( USBConfigurationDescriptorPtr pConfigDesc, int protocol )
  537. {
  538.     //
  539.     //    find a print interface (and alternateSetting) which allows 
  540.     //        the desired protocol
  541.     //
  542.     //
  543.     int                                numInterfaces;
  544.     UInt32                            totalLength;
  545.     void                                *pEndOfDescriptors;
  546.     USBInterfaceDescriptorPtr    pMyIntDesc;
  547.     USBDescriptorHeaderPtr        pCurrentDesc;
  548.     Ptr                                p;
  549.     
  550.     totalLength = USBToHostWord( pConfigDesc->totalLength );
  551.     pEndOfDescriptors = (Ptr)pConfigDesc + totalLength;                // get the total length and add it to the start of the config space
  552.     pCurrentDesc = (USBDescriptorHeaderPtr)pConfigDesc;                // point the currentdesc to the start of the config space
  553.     
  554.     numInterfaces = 0;
  555.     while (pCurrentDesc < pEndOfDescriptors)                        // as long as we haven't exhausted all the descriptors
  556.     {
  557.         if (pCurrentDesc->descriptorType == kUSBInterfaceDesc)    // look at the current descriptor
  558.         {
  559.             pMyIntDesc = (USBInterfaceDescriptorPtr)pCurrentDesc;    // if it's an interface descriptor
  560.             if (pMyIntDesc->interfaceClass == kUSBPrintClass &&
  561.                     pMyIntDesc->interfaceSubClass == kUSBPrintSubClass &&
  562.                     pMyIntDesc->interfaceProtocol == protocol    )        // see if it's the requested descriptor
  563.                 break;
  564.         }
  565.         if ( pCurrentDesc->length == 0 )
  566.         {
  567.             IF_DEBUG( DebugStr( "\pFindInterface NULL" ) );
  568.             pCurrentDesc = pEndOfDescriptors;    // shouldn't happen
  569.             break;
  570.         }
  571.         p = (Ptr)pCurrentDesc + pCurrentDesc->length;                    // Nope, that either wasn't an interface descriptor
  572.         pCurrentDesc = (USBDescriptorHeaderPtr) p;
  573.     }                                                            // or it was, but not the droid we're looking for.
  574.     return pCurrentDesc < pEndOfDescriptors? (struct USBInterfaceDescriptor *) pCurrentDesc: NULL;
  575.  
  576. }
  577.  
  578. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  579.     Name:        FindEndpoint
  580.  
  581.     Input Parameters:    
  582.         pInterface            pointer to interface descriptor
  583.         kind                    kUSBIn, kUSBOut
  584.         
  585.     Output Parameters:
  586.         result                pointer to bulk endpoint descriptor
  587.     
  588.     Description:
  589.  
  590.     Change History:
  591.          8 Jun 1998,    oja:        Original version.
  592. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  593.  
  594. static USBEndPointDescriptor *
  595. FindEndpoint( USBInterfaceDescriptor *pInterface, int kind )
  596. {
  597.     USBEndPointDescriptor    *pEndpoint = (USBEndPointDescriptor *) (pInterface->length + (Ptr) pInterface),
  598.                                     *pEndOfEndpoints = pEndpoint + pInterface->numEndpoints;
  599.  
  600.     UInt8                            addressMask = kind == kUSBIn? 0x80: 0;
  601.     while ( pEndpoint < pEndOfEndpoints )
  602.     {
  603.         Ptr    p = (Ptr) pEndpoint;
  604.         if ( pEndpoint->attributes == 2 && ((pEndpoint->endpointAddress & addressMask) == addressMask) )
  605.             break;
  606.         
  607.         p += pEndpoint->length;
  608.         pEndpoint = (USBEndPointDescriptor *) p;
  609.     }
  610.     
  611.     return pEndpoint < pEndOfEndpoints? pEndpoint: NULL;
  612. }
  613.  
  614. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  615.     Name:        ParseCapability
  616.  
  617.     Input Parameters:    
  618.         capability            pointer to 1284-1994 capability string
  619.         attribute            pointer to c-string key we're retrieving (terminate with colon)
  620.         *result_length        maximum length of the result 
  621.         
  622.     Output Parameters:
  623.         result                c-string which followed the key and was terminated by semi-colon
  624.                                 (semi-colon has been stripped)
  625.         *result_length        actual length of the result (may be zero)
  626.     
  627.     Description:
  628.         Search for "attribute" in the 1284 "capability" string
  629.         The identifier is terminated with a semi-colon
  630.  
  631.         Return the attribute in result
  632.             null-string if attribute not found.
  633.  
  634.     Change History:
  635.         20 Jul 1998,    oja:        fix computation of target_length
  636.         28 Feb 1998,    oja:        Original version.
  637. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  638. static void
  639. ParseCapability(
  640.     unsigned char    *capability,
  641.     unsigned char    *attribute,
  642.     unsigned char    *result,
  643.     int                *result_length 
  644. )
  645. {
  646.     //
  647.     //    search for "attribute" in the 1284 "capability" string
  648.     //
  649.     //    the identifier is terminated with a semi-colon
  650.     //
  651.     //    return the attribute in result
  652.     //            null-string if attribute not found
  653.     //
  654.     //    <to do> skip blanks, isolate colon, skip blanks
  655.     //
  656.     int                source_length,
  657.                         target_length;
  658.     unsigned char    *source,
  659.                         *target,
  660.                         *destination;
  661.     //
  662.     //    begin a brute force search
  663.     //
  664.     source = attribute;
  665.     source_length = cstrlen((char *)attribute );
  666.  
  667.     target = capability + 2;    // skip the length
  668.     target_length =  capability[1] | (capability[0] << 8);
  669.     target_length -= 2;            // don't count the length
  670.     while ( target_length >= source_length )
  671.     {
  672.         if ( memcmp( source, target, source_length ) == 0 )
  673.             break;
  674.         --target_length;
  675.         ++target;
  676.     }
  677.  
  678.     destination = result;
  679.     *destination = 0;    // empty result
  680.  
  681.     target += source_length;
  682.     target_length -= source_length;    // skip the attribute string
  683.  
  684.     if ( target_length > 0 )
  685.     {
  686.         //
  687.         //    we found the attribute in the capability string
  688.         //
  689.         while ( destination - result < *result_length )    // arbitrarily limit reply
  690.         {
  691.             if ( *target == ';' )
  692.                 break;
  693.             *destination++ = *target++;        // copy a byte of attribute over
  694.         }
  695.         *destination++ = '\0';                        // trailing NUL
  696.         *result_length = destination - result;    // report the length of the data (with trailing NUL)
  697.     }
  698. }
  699.  
  700.  
  701. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  702.     Name:        GetClass
  703.  
  704.     Input Parameters:    
  705.         capability            pointer to 1284-1994 capability string
  706.         *result_length        maximum length of the result 
  707.         
  708.     Output Parameters:
  709.         result                c-string extracted from the MODEL key
  710.         *result_length        actual length of the result  (may be zero)
  711.         
  712.     Description:
  713.         CLASS is a Microsoft extension to the 1284-capability string
  714.         if we don't find it
  715.             we assume that the device is a printer
  716.         Since the USB hardware has already indicated this, we're really allowing
  717.         devices which aren't printers to be reached via the DRVRs we've installed.
  718.  
  719.     Change History:
  720.         26 Mar 1998,    oja:        result_length is output too
  721.         28 Feb 1998,    oja:        Original version.
  722. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  723. static void
  724. GetClass(
  725.     unsigned char    *capability,
  726.     unsigned char    *result,
  727.     int                *result_length
  728. )
  729. {
  730.     //
  731.     //    We supply the upper-case PRINTER to be consistent with 1284-1994
  732.     //        if we don't find a class.
  733.     //
  734.     ParseCapability( capability, (unsigned char *) "CLASS:", result, result_length);
  735.     if ( *result == '\0' )
  736.         ParseCapability( capability, (unsigned char *) "CLS:", result, result_length);
  737.     if ( *result == '\0' )
  738.         cstrcpy( (char *)result, "PRINTER" );
  739. }
  740.  
  741.  
  742. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  743.     Name:        GetModel
  744.  
  745.     Input Parameters:    
  746.         capability            pointer to 1284-1994 capability string
  747.         *result_length        maximum length of the result 
  748.         
  749.     Output Parameters:
  750.         result                c-string extracted from the MODEL key
  751.         *result_length        actual length of the result  (may be zero)
  752.             
  753.     Description:
  754.         MODEL is a required field of the 1284-capability string
  755.         MODEL may be abbreviated MDL
  756.  
  757.     Change History:
  758.         26 Mar 1998,    oja:        result_length is output too
  759.         28 Feb 1998,    oja:        Original version.
  760. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  761. static void
  762. GetModel(
  763.     unsigned char    *capability, 
  764.     unsigned char    *result,
  765.     int                *result_length
  766. )
  767. {
  768.     //
  769.     //    Most manufacturers abbreviate, so we search for MDL first
  770.     //
  771.     ParseCapability( capability, (unsigned char *) "MDL:", result, result_length );
  772.     if ( *result == '\0' )
  773.         ParseCapability( capability, (unsigned char *) "MODEL:", result, result_length );
  774. }
  775.  
  776.  
  777. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  778.     Name:        GetCommandSet
  779.  
  780.     Input Parameters:    
  781.         
  782.     Output Parameters:
  783.         
  784.     Description:
  785.  
  786.     Change History:
  787.         28 Feb 1998,    oja:        Original version.
  788. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  789. static void
  790. GetCommandSet(
  791.     unsigned char *capability, 
  792.     unsigned char *result,
  793.     int *result_length
  794. )
  795. {
  796.     //
  797.     //    COMMAND-SET is a required field of the 1284-capability string
  798.     //    COMMAND-SET may be abbreviated CMD
  799.     //
  800.     ParseCapability( capability, (unsigned char *) "CMD:", result, result_length );
  801.     if ( *result == '\0' )
  802.         ParseCapability( capability, (unsigned char *) "COMMAND-SET:", result, result_length );
  803. }
  804.  
  805. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  806.     Name:        GetManufacturer
  807.  
  808.     Input Parameters:    
  809.         
  810.     Output Parameters:
  811.         
  812.     Description:
  813.  
  814.     Change History:
  815.         26 Jun 1998,    oja:        Original version.
  816. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  817. static void
  818. GetManufacturer(
  819.     unsigned char *capability, 
  820.     unsigned char *result,
  821.     int *result_length
  822. )
  823. {
  824.     //
  825.     //    MANUFACTURER is a required field of the 1284-capability string
  826.     //    MANUFACTURER may be abbreviated MFG
  827.     //
  828.     ParseCapability( capability, (unsigned char *) "MFG:", result, result_length );
  829.     if ( *result == '\0' )
  830.         ParseCapability( capability, (unsigned char *) "MANUFACTURER:", result, result_length );
  831. }
  832.  
  833. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  834.     Name:        OpenBulkEndpoint
  835.  
  836.     Input Parameters:    
  837.         pPrinterPB
  838.         refCon
  839.  
  840.     Output Parameters:
  841.         pb->usbReference    on (asynchronous) completion
  842.         
  843.     Description:
  844.         Asynchronous completion.
  845.  
  846.         Open a bulkIn or bulkOut endpoint
  847.  
  848.     Change History:
  849.         21 Jul 1998,    oja:        call SetNullParamBlock
  850.         28 Feb 1998,    oja:        Original version.
  851. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  852. OSStatus
  853. OpenBulkEndpoint(
  854.     struct usbPrinterPBStruct    *pPrinterPB,
  855.     UInt32                            refCon
  856. )
  857. {
  858.  
  859.     OSStatus                        err;
  860.     USBEndPointDescriptor    *eDesc;
  861.     USBPB                            *pb = &pPrinterPB->pb;
  862.     //
  863.     // The params are set up correctly so open it
  864.     //    asynchronous completion will set usbReference to a pipe
  865.     //
  866.     SetNullUSBParamBlock(pPrinterPB->device,  pb );
  867.     switch (refCon)
  868.     {
  869.     case kOpenBulkOutPipe:
  870.         eDesc = FindEndpoint( pPrinterPB->interface, kUSBOut );
  871.         pPrinterPB->writeDescriptor = eDesc;
  872.         pb->usbFlags = kUSBOut;
  873.         break;
  874.     case kOpenBulkInPipe:
  875.         eDesc = FindEndpoint( pPrinterPB->interface, kUSBIn );
  876.         pPrinterPB->readDescriptor = eDesc;
  877.         pb->usbFlags = kUSBIn;
  878.         break;
  879.     default:
  880.         USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "OpenEndpoint undefined refCon",1);
  881.         break;
  882.     }
  883.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  884.  
  885.     pb->pbVersion = kUSBCurrentPBVersion;
  886.     pb->usbClassType = kUSBBulk;
  887.     pb->usbOther = eDesc->endpointAddress & ~0x80;
  888.     pb->usbWValue = USBToHostWord(eDesc->maxPacketSize);
  889.     pb->usbRefcon = refCon | kTransactionPending | kAsyncTransaction;
  890.  
  891.     err = USBOpenPipe( pb );
  892.     if(immediateError(err))
  893.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "OpenEndpoint Failed Open pipe", 0);
  894.  
  895.     return err;
  896. }
  897.  
  898. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  899.     Name:        DeregisterDevice
  900.  
  901.     Input Parameters:    
  902.         pPrinterPB
  903.  
  904.     Output Parameters:
  905.         <none>
  906.         
  907.     Description:
  908.         remove the device from the name registry
  909.  
  910.     Change History:
  911.         11 Jun 1998,    oja:        test from RegistryCStrEntryLookup was wrong direction
  912.         17 Apr 1998,    oja:        Original version.
  913. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  914. static OSStatus
  915. DeregisterDevice( struct usbPrinterPBStruct *pPrinterPB )
  916. {
  917.     OSStatus        err;
  918.     RegEntryID    self;
  919.  
  920.     RegistryEntryIDInit( &self );
  921.     err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  922.     if ( err == noErr )
  923.     {
  924.         err = RegistryEntryDelete( &self);
  925.     }
  926.     RegistryEntryIDDispose(&self);
  927.     if (err == noErr &&  pPrinterPB->outRefNum != -1 )
  928.         err = TradRemoveDriver( pPrinterPB->outRefNum, false );
  929.     if (err == noErr &&  pPrinterPB->inRefNum != -1 )
  930.         err = TradRemoveDriver( pPrinterPB->inRefNum, false );
  931.     
  932.     return err;
  933. }
  934.  
  935. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  936.     Name:        RegisterDevice
  937.  
  938.     Input Parameters:    
  939.         pPrinterPB
  940.  
  941.     Output Parameters:
  942.         <none>
  943.         
  944.     Description:
  945.         add the device into the name registry; we can't insert just the node
  946.         if the parent nodes aren't present.
  947.  
  948.         if it isn't present
  949.             insert the device CLASS into the registry
  950.         if it isn't present
  951.             insert the device MODEL into the registry
  952.         finally insert the device itself into the registry
  953.             we're careful to rename multiple devices
  954.  
  955.     Change History:
  956.         16 Jul 1998,    oja:        fix params to sprintf
  957.          8 Jun 1998,    oja:        don't use register param (CW build)
  958.         26 Mar 1998,    oja:        only register significant part of drvrNames 
  959.                                         log null model name to Expert
  960.                                         register command set 
  961.         28 Feb 1998,    oja:        Original version.
  962. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  963. static OSStatus
  964. RegisterDevice( struct usbPrinterPBStruct *pPrinterPB )
  965. {
  966.     //
  967.     //    add the device into the name registry
  968.     //    if it isn't present
  969.     //        insert the device CLASS into the registry
  970.     //    if it isn't present
  971.     //        insert the device MODEL into the registry
  972.     //    finally insert the device itself into the registry
  973.     //        we're careful to rename multiple devices
  974.     //
  975.     Str255        identification,
  976.                     devclass,
  977.                     model,
  978.                     commands;
  979.     RegEntryID    parent, where, self;
  980.     OSStatus        err;
  981.     int            model_length,
  982.                     command_length,
  983.                     class_length;
  984.  
  985.     class_length = sizeof(devclass);
  986.     GetClass( pPrinterPB->capabilityString, devclass, &class_length );
  987.  
  988.     command_length = sizeof(commands);
  989.     GetCommandSet(pPrinterPB->capabilityString, commands, &command_length );
  990.  
  991.     cstrcpy( (char *)pPrinterPB->name, (char *)"Devices:device-tree:" );
  992.     cstrcat( (char *)pPrinterPB->name, (char *)devclass );
  993.     
  994.     RegistryEntryIDInit( &where );
  995.     err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name, &where );
  996.     if ( err == nrPathNotFound ) 
  997.     {
  998.         //    class not in registry
  999.         //        create a node for all devices of this CLASS
  1000.         //
  1001.         RegistryEntryIDInit( &parent );
  1002.         err = RegistryCStrEntryLookup( nil, "Devices:device-tree:" , &parent );
  1003.         if ( err == noErr )
  1004.             err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &where );
  1005.         RegistryEntryIDDispose(&parent);
  1006.  
  1007.     }
  1008.     //
  1009.     //    add this model into the name registry of this class
  1010.     //
  1011.     if ( err == noErr )
  1012.     {
  1013.         model_length = sizeof(model);
  1014.         GetModel( pPrinterPB->capabilityString, model, &model_length );
  1015.         if ( model_length != 0 )
  1016.         {
  1017.             cstrcpy( (char *)pPrinterPB->name, "Devices:device-tree:" );
  1018.             cstrcat( (char *)pPrinterPB->name, (char *)devclass );
  1019.             cstrcat( (char *)pPrinterPB->name, ":" );
  1020.             cstrcat( (char *)pPrinterPB->name, (char *)model );
  1021.             RegistryEntryIDInit( &self );
  1022.             err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  1023.             if ( err != noErr )
  1024.             {
  1025.                 // model not in registry
  1026.                 err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
  1027.             }
  1028.             RegistryEntryIDDispose(&self);
  1029.         }
  1030.     }
  1031.     //
  1032.     //    add this instance of this model of this class
  1033.     //        into the name registry
  1034.     //
  1035.     if ( model_length == 0  )
  1036.     {
  1037.         //
  1038.         //    possibly the cable isn't firmly connected or the printer isn't switched on
  1039.         //
  1040.         err = kUSBInternalErr;
  1041.         USBExpertFatalError(pPrinterPB->device, err, kStrPrinterClass "\pModel undefined", 0);
  1042.     }
  1043.     if ( err == noErr )
  1044.     {
  1045.         //
  1046.         //    start off by identifying the device simply by the model name
  1047.         //        increment the numeric suffix until we successfully registry the device
  1048.         //
  1049.         Str32    suffix;
  1050.         int    numeric_suffix;
  1051.  
  1052.         cstrcpy( (char *)identification, (char *)model );
  1053.         RegistryEntryIDInit( &self );
  1054.         for ( numeric_suffix = 1; numeric_suffix < MAX_SUFFIX; ++numeric_suffix )
  1055.         {
  1056.             cstrcpy( (char *)pPrinterPB->name, "Devices:device-tree:" );
  1057.             cstrcat( (char *)pPrinterPB->name, (char *)devclass );
  1058.             cstrcat( (char *)pPrinterPB->name, ":" );
  1059.             cstrcat( (char *)pPrinterPB->name, (char *)model );
  1060.             cstrcat( (char *)pPrinterPB->name, ":" );
  1061.             cstrcat( (char *)pPrinterPB->name, (char *)identification );
  1062.             err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  1063.             if ( err != noErr )
  1064.             {
  1065.                 // enter device in registry
  1066.                 err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
  1067.                 if ( err == noErr )
  1068.                     err = RegistryPropertyCreate( &self, "drvrOut", &pPrinterPB->driverOutName, 1 + pPrinterPB->driverOutName[0] );
  1069.                 if ( err == noErr )
  1070.                     err = RegistryPropertyCreate( &self, "outRef", &pPrinterPB->outRefNum, sizeof(pPrinterPB->outRefNum) );
  1071.                 if ( err == noErr )
  1072.                     err = RegistryPropertyCreate( &self, "drvrIn", &pPrinterPB->driverInName, 1 + pPrinterPB->driverInName[0] );
  1073.                 if ( err == noErr )
  1074.                     err = RegistryPropertyCreate( &self, "inRef", &pPrinterPB->inRefNum, sizeof(pPrinterPB->inRefNum) );
  1075.                 if ( err == noErr )
  1076.                     err = RegistryPropertyCreate( &self, "privateData", &pPrinterPB, sizeof(pPrinterPB) );
  1077.                 if ( err == noErr )
  1078.                     err = RegistryPropertyCreate( &self, "read", &pPrinterPB->r, sizeof(QueueUSBReadUPP) );
  1079.                 if ( err == noErr )
  1080.                     err = RegistryPropertyCreate( &self, "write", &pPrinterPB->w, sizeof(QueueUSBWriteUPP) );
  1081.                 if ( err == noErr && command_length > 0 )
  1082.                     err = RegistryPropertyCreate( &self, "command-set", &commands, command_length );
  1083.                 break;
  1084.             }
  1085.             //
  1086.             //    if this name didn't succeed
  1087.             //        try the next numeric suffix
  1088.             //
  1089.             sprintf( (char *)suffix, " %d", numeric_suffix );
  1090.             cstrcpy( (char *)identification, (char *)model );
  1091.             cstrcat( (char *)identification, (char *)suffix );
  1092.         }
  1093.         RegistryEntryIDDispose(&self);
  1094.     }
  1095.     USBExpertStatus( pPrinterPB->device, pPrinterPB->name, err );
  1096.     RegistryEntryIDDispose(&where);
  1097.  
  1098.     LOGGING( logfile = fopen( "USBPrinter.log", "wb+" ) );
  1099.     return err;
  1100. }
  1101.  
  1102. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1103.     Name:        LoadResources
  1104.  
  1105.     Input Parameters:
  1106.         pPrinterPB            pointer to class driver's private storage
  1107.         
  1108.     Output Parameters:
  1109.         OSStatus                resource load error
  1110.         
  1111.     Description:
  1112.         Initialize time is the only safe time to to load resources from our file.
  1113.         Here's where we load resources and detach them from the resource manager.
  1114.         Later we'll use these private copies instead of GetResource calls.
  1115.         
  1116.         Using the file spec that we got from the CFMInitialization routine, open
  1117.         our resource fork.
  1118.  
  1119.     Change History:
  1120.         11 Jun 1998,    oja:        removed hardcoded filename, use printerClassDriverFileSpec
  1121.         20 Mar 1998,    oja:        Original version.
  1122. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1123. static OSStatus
  1124. LoadResources( struct usbPrinterPBStruct *pPrinterPB )
  1125. {
  1126.     short            rf = -1;                // class driver resource fork
  1127.     OSStatus        err;
  1128.  
  1129.     //
  1130.     //    open the resource fork of this class driver
  1131.     //
  1132.     rf = FSpOpenResFile( &printerClassDriverFileSpec,fsRdPerm );
  1133.     err = ResError();
  1134.     
  1135.     //
  1136.     //    load the DRVR that we'll stick in the unit table
  1137.     //
  1138.     pPrinterPB->hDrvr = NULL;
  1139.     if ( err == noErr )
  1140.     {
  1141.         pPrinterPB->hDrvr = (DRVRHeaderHandle) Get1Resource( 'DRVR',  kUSBParallelDrvrRsrcID );
  1142.         if ( pPrinterPB->hDrvr != NULL )
  1143.             DetachResource( (Handle) pPrinterPB->hDrvr );
  1144.         err = ResError();
  1145.     }
  1146.     
  1147.     if ( rf != -1 )
  1148.         CloseResFile( rf );
  1149.     
  1150.     return err;
  1151. }
  1152.  
  1153. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1154.     Name:        InstallDrivers
  1155.  
  1156.     Input Parameters:
  1157.         pPrinterPB
  1158.         
  1159.     Output Parameters:
  1160.         OSStatus            error code
  1161.         
  1162.     Description:
  1163.         install read and write drivers in the unit table
  1164.             we have separate drivers so that we can support a full-duplex protocol
  1165.         rename the driver we just installed (so multiple copies don't conflict)
  1166.         We use the DRVR -refnum-1 so that the driver name has the same hex chars
  1167.             as the driver number (for manual verification in MacsBug)
  1168.  
  1169.     Change History:
  1170.         13 Jul 1998,    oja:        init err to noErr
  1171.         26 Mar 1998,    oja:        Use refnum -1, use infix location to enumerate
  1172.                                         DRVR
  1173.         28 Feb 1998,    oja:        Original version.
  1174. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1175. static OSStatus
  1176. InstallDrivers( struct usbPrinterPBStruct *pPrinterPB )
  1177. {
  1178.     //
  1179.     //    install the driver in the unit table
  1180.     //    rename the driver we just installed (so multiple copies don't conflict)
  1181.     //    
  1182.     short            refNum;                // DRVR refNum
  1183.     OSStatus        err =  paramErr;    // couldn't find driver
  1184.  
  1185.     if ( pPrinterPB->hDrvr != NULL )
  1186.         err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->outRefNum );
  1187.  
  1188.     if ( err == noErr )
  1189.     {
  1190.         UnitNumber        unit;
  1191.         DriverFlags        flags;
  1192.         DRVRHeaderPtr    hdr;
  1193.         unsigned char    *suffix,        // append "In" and "Out"
  1194.                             *infix;        // driver reference number follows the ".USB"
  1195.  
  1196.         TradGetDriverInformation( pPrinterPB->outRefNum, &unit, &flags, pPrinterPB->driverOutName, &hdr );
  1197.         BlockMove( pPrinterPB->driverOutName, pPrinterPB->driverInName, 1 + pPrinterPB->driverOutName[0] );
  1198.         
  1199.         suffix = pPrinterPB->driverOutName + pPrinterPB->driverOutName[0] - 2;
  1200.         infix = pPrinterPB->driverOutName + kDrvrFirstDigit;
  1201.         infix[0] = HiHex( -pPrinterPB->outRefNum -1 );
  1202.         infix[1] = LoHex( -pPrinterPB->outRefNum -1 );
  1203.         suffix[0] = 'O';
  1204.         suffix[1] = 'u';
  1205.         suffix[2] = 't';
  1206.         TradRenameDriver( pPrinterPB->outRefNum, pPrinterPB->driverOutName );
  1207.         //
  1208.         //    set the driver data to point to our parameter block
  1209.         //
  1210.         err = OpenDriver( pPrinterPB->driverOutName, &refNum );
  1211.         if ( err == noErr )
  1212.         {
  1213.             struct usbPrinterPBStruct *param = pPrinterPB;
  1214.             err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
  1215.             CloseDriver( refNum );
  1216.         }
  1217.         err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->inRefNum );
  1218.         if ( err == noErr )
  1219.         {
  1220.             
  1221.             suffix = pPrinterPB->driverInName + pPrinterPB->driverInName[0] - 1;
  1222.             infix = pPrinterPB->driverInName + kDrvrFirstDigit;
  1223.             infix[0] = HiHex( -pPrinterPB->inRefNum -1 );
  1224.             infix[1] = LoHex( -pPrinterPB->inRefNum -1 );
  1225.             suffix[0] = 'I';
  1226.             suffix[1] = 'n';
  1227.             TradRenameDriver( pPrinterPB->inRefNum, pPrinterPB->driverInName );
  1228.             //
  1229.             //    set the driver data to point to our parameter block
  1230.             //
  1231.             err = OpenDriver( pPrinterPB->driverInName, &refNum );
  1232.             if ( err == noErr )
  1233.             {
  1234.                 struct usbPrinterPBStruct *param = pPrinterPB;
  1235.                 err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
  1236.                 CloseDriver( refNum );
  1237.             }
  1238.         }
  1239.     }
  1240.  
  1241.     return err;
  1242. }
  1243.  
  1244. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1245.     Name:        GetCapability
  1246.  
  1247.     Input Parameters:    
  1248.         
  1249.     Output Parameters:
  1250.         
  1251.     Description:
  1252.         Asynchronous completion.
  1253.  
  1254.     Change History:
  1255.         28 Feb 1998,    oja:        Original version.
  1256. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1257. static void
  1258. GetCapability( struct usbPrinterPBStruct *pPrinterPB, unsigned char *p, int length )
  1259. {
  1260.     //
  1261.     //    queue a transaction to retrieve the 1284 capability string
  1262.     //        we must have assigned the interface by this point since the capability string
  1263.     //        may vary with the interface
  1264.     //
  1265.     OSStatus        err;
  1266.     USBPB            *pb = &pPrinterPB->pb;
  1267.     
  1268.     pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  1269.  
  1270.     pb->usbBRequest = kUSBPrintClassGetDeviceID;
  1271.     pb->usbWValue = (pPrinterPB->config)->configValue;        // configuration
  1272.     pb->usbWIndex = ((pPrinterPB->interface)->interfaceNumber<<8) | (pPrinterPB->interface)->alternateSetting;
  1273.  
  1274.     pb->usbReqCount = length;
  1275.     pb->usbBuffer = p;
  1276.  
  1277.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1278.     pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
  1279.  
  1280.     err = USBDeviceRequest(pb);
  1281.     if(immediateError(err))
  1282.     {
  1283.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetCapability", 0);
  1284.     }
  1285. }
  1286.  
  1287. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1288.     Name:        IsLucentCable
  1289.  
  1290.     Input Parameters:    
  1291.         dev            USB device descriptor
  1292.         
  1293.     Output Parameters:
  1294.         Return 1 if the USB device is a USB-parallel cable
  1295.         
  1296.     Description:
  1297.         
  1298.  
  1299.     Change History:
  1300.         28 Feb 1998,    oja:        Original version.
  1301. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1302. static int
  1303. IsLucentCable( USBDeviceDescriptor    *dev )
  1304. {
  1305.     return ( USBToHostWord(dev->vendor) == 0x47E && USBToHostWord(dev->product) == 0x1001 )? 1: 0;
  1306. }
  1307.  
  1308.  
  1309. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1310.     Name:        SetInterface
  1311.  
  1312.     Input Parameters:    
  1313.         
  1314.     Output Parameters:
  1315.         
  1316.     Description:
  1317.         Asynchronous completion.
  1318.  
  1319.     Change History:
  1320.         28 Feb 1998,    oja:        Original version.
  1321. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1322. static void
  1323. SetInterface( USBPB *pb, int whichInterface, int whichAlternate )
  1324. {
  1325.     //
  1326.     //    the device has multiple printer interfaces
  1327.     //        select either the bi-directional or uni-directional interface
  1328.     OSStatus    err;
  1329.  
  1330.     pb->usbBMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBInterface);
  1331.  
  1332.     pb->usbBRequest = kUSBRqSetInterface;
  1333.     pb->usbWValue = whichAlternate;        // alternate setting
  1334.     pb->usbWIndex = whichInterface;        // interface
  1335.  
  1336.     pb->usbReqCount = 0;
  1337.     pb->usbBuffer = NULL;
  1338.  
  1339.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1340.     pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
  1341.  
  1342.     err = USBDeviceRequest(pb);
  1343.     if(immediateError(err))
  1344.     {
  1345.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "SetInterface", 0);
  1346.     }
  1347. }
  1348.  
  1349. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1350.     Name:        GetInterface
  1351.  
  1352.     Input Parameters:    
  1353.         
  1354.     Output Parameters:
  1355.         
  1356.     Description:
  1357.         Asynchronous completion.
  1358.  
  1359.     Change History:
  1360.         28 Feb 1998,    oja:        Original version.
  1361. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1362. static void
  1363. GetInterface( USBPB *pb, UInt8 *alt )
  1364. {
  1365.     //
  1366.     //    make sure we account for any alternate interface currently in use by the device
  1367.     //
  1368.     OSStatus    err;
  1369.  
  1370.     pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBInterface);
  1371.  
  1372.     pb->usbBRequest = kUSBRqGetInterface;
  1373.     pb->usbWValue = 0; 
  1374.     pb->usbWIndex = 0;
  1375.  
  1376.     pb->usbReqCount = sizeof(UInt8);        // single byte is requested
  1377.     pb->usbBuffer = alt;
  1378.  
  1379.     pb->usbStatus = 0;
  1380.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1381.     pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
  1382.  
  1383.     err = USBDeviceRequest(pb);
  1384.     if(immediateError(err))
  1385.     {
  1386.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetInterface", 0);
  1387.     }
  1388. }
  1389.  
  1390. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1391.     Name:        GetConfigurationDescriptor
  1392.  
  1393.     Input Parameters:    
  1394.         pb                        USB parameter block
  1395.         pConfiguration        storage for the reply
  1396.         length                number of bytes allocated for the reply
  1397.         
  1398.     Output Parameters:
  1399.         pConfiguration        the device's configuration descriptor (possibly truncated)
  1400.         
  1401.     Description:
  1402.         Asynchronous completion.
  1403.  
  1404.         Retrieve the device's configuration descriptor. Note that we may not get
  1405.         the full configuration--the client must read the length in the reply and
  1406.         determine if the call successfully completed retrieval of the full config-
  1407.         uration descriptor.
  1408.  
  1409.     Change History:
  1410.         28 Feb 1998,    oja:        Original version.
  1411. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1412. static void
  1413. GetConfigurationDescriptor(
  1414.     USBPB *pb,
  1415.     USBConfigurationDescriptorPtr pConfiguration, 
  1416.     int length
  1417. )
  1418. {
  1419.     OSStatus    err;
  1420.  
  1421.     pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBDevice);
  1422.  
  1423.     pb->usbBRequest = kUSBRqGetDescriptor;
  1424.     pb->usbWValue = (kUSBConfDesc<<8) + 0; 
  1425.     pb->usbWIndex = 0;    //language
  1426.  
  1427.     pb->usbReqCount = length;
  1428.     pb->usbBuffer = pConfiguration;
  1429.  
  1430.     pb->usbStatus = 0;
  1431.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1432.     pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
  1433.  
  1434.     err = USBDeviceRequest(pb);
  1435.     if(immediateError(err))
  1436.     {
  1437.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetConfigurationDescriptor", 0);
  1438.     }
  1439. }
  1440.  
  1441. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1442.     Name:        ReadCompletion
  1443.  
  1444.     Input Parameters:    
  1445.         pb                        USB parameter block
  1446.         
  1447.     Output Parameters:
  1448.         <none>
  1449.  
  1450.     Description:
  1451.         USB read requests complete here.
  1452.         We dequeue the MacOS DRVR read requests
  1453.  
  1454.     Change History:
  1455.         10 Aug 1998,    oja:        set readDrvr.ctl to NULL when finished
  1456.         28 Jul 1998,    oja:        breakdown transactions into MAX_USB_TRANSFER_SIZE
  1457.         27 Jul 1998,    oja:        lock memory (UIM doesn't do this properly)
  1458.         20 Jul 1998,    oja:        retry transactions
  1459.          8 Jun 1998,    oja:        clear stalls on error
  1460.         28 Feb 1998,    oja:        Original version.
  1461. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1462. static void
  1463. ReadCompletion(USBPB *pb)
  1464. {
  1465.     //    call the user completion routine
  1466.     struct usbPrinterPBStruct
  1467.                     *pPrinterPB =  (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1468.     IOParamPtr     clientParam = pPrinterPB->readDrvr.pb;
  1469.     OSStatus        err = pb->usbStatus;
  1470.  
  1471. #if MACSBUG_ON_READ_COMPLETE
  1472.     Str255    text;
  1473.     sprintf( (char *)text, " PrinterClass Read Complete(%d): %d", pb->usbStatus, pb->usbActCount );
  1474.     text[0] = cstrlen((char *)text); // c2pstr
  1475.     DebugStr( text );
  1476. #endif
  1477.  
  1478. #if DOUBLE_BUFFER
  1479.     //
  1480.     //    copy the user data from our page aligned buffer
  1481.     //
  1482.     if ( pb->usbActCount > 0 )
  1483.         BlockCopy( pPrinterPB->pageReadAlignedBuffer, clientParam->ioBuffer + clientParam->ioActCount, pb->usbActCount );
  1484. #endif
  1485.     //    update the amount of data actually transferred
  1486.     clientParam->ioActCount += pb->usbActCount;
  1487.  
  1488.     switch( pb->usbStatus )
  1489.     {
  1490.         //
  1491.         //    only retry low level hardware problems
  1492.         //        note: abort transactions will end up here as well
  1493.         //
  1494.     case kUSBLinkErr:
  1495.     case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  1496.     case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  1497.     case kUSBDataToggleErr:                        /*  Pipe stall, Bad data toggle */
  1498.     case kUSBNotRespondingErr:                    /*  Pipe stall, No device, device hung */
  1499.     case kUSBPIDCheckErr:                        /*  Pipe stall, PID CRC error */
  1500.     case kUSBWrongPIDErr:                        /*  Pipe stall, Bad or wrong PID */
  1501.         if (  --(pPrinterPB->readRetryCount) > 0 ) 
  1502.         {
  1503.             // we got an error, and we still want to retry, clear any stalls
  1504.             USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "ReadCompletion retry" , pb->usbStatus );
  1505.             USBClearPipeStallByReference(pPrinterPB->readPipe);
  1506.             pb->usbStatus = noErr;
  1507.         }
  1508.         break;
  1509.     case kUSBAbortedError:                        /* user cancel, or hot unplug */
  1510.         USBClearPipeStallByReference(pPrinterPB->readPipe);
  1511.         USBClearPipeStallByReference(pPrinterPB->device);
  1512.         break;
  1513.         //
  1514.         //    any other error will be reported to the client
  1515.         //
  1516.     default:
  1517.     case noErr:
  1518.         break;
  1519.     }
  1520.     if ( pb->usbStatus == noErr &&                                     // there were no problems
  1521.         pb->usbActCount >= pb->usbReqCount &&                        // we got all the data we requested
  1522.         clientParam->ioActCount < clientParam->ioReqCount )    // we still want more data
  1523.     {
  1524.         //
  1525.         //    haven't finish the client's request
  1526.         //        update the pointers and start another bulkOut transaction
  1527.         //
  1528. #if LOCK_MEMORY
  1529.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1530.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion UnlockMem failed" ) );
  1531. #endif
  1532.         pb->usbBuffer = clientParam->ioBuffer + clientParam->ioActCount;
  1533.         pb->usbReqCount = clientParam->ioReqCount - clientParam->ioActCount;
  1534. #if MAX_USB_TRANSFER_SIZE
  1535.         if ( pb->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1536.             pb->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1537. #endif
  1538. #if DOUBLE_BUFFER
  1539.         //
  1540.         //    make sure we have enough room in our buffer
  1541.         //
  1542.         if ( pb->usbReqCount > pPrinterPB->pageReadAlignedBufferSize )
  1543.             pb->usbReqCount = pPrinterPB->pageReadAlignedBufferSize;
  1544.         pb->usbBuffer = pPrinterPB->pageReadAlignedBuffer;
  1545. #endif
  1546. #if LOCK_MEMORY
  1547.         err = LockMemory( pb->usbBuffer, pb->usbReqCount );
  1548.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion LockMem failed" ) );
  1549.         if ( err == noErr )
  1550. #endif
  1551.             err = USBBulkRead( pb );
  1552.         if ( immediateError(err) )
  1553.         {
  1554.             USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "ReadCompletion finish immed err" , err );
  1555.  
  1556.             pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1557.             if ( pPrinterPB->readDrvr.ctl != NULL )
  1558.                 CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, err, clientParam, pPrinterPB->readDrvr.ctl ); 
  1559.             pPrinterPB->readDrvr.ctl = NULL;
  1560.         }
  1561.     }
  1562.     else
  1563.     {
  1564.         //
  1565.         //        either we have an error which we're not retrying
  1566.         //            or we successfully completed
  1567.         //
  1568. #if LOCK_MEMORY
  1569.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1570.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion concluded UnlockMem failed" ) );
  1571. #endif
  1572.         IF_DEBUG( if (pb->usbStatus != noErr) USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "ReadCompletion Error" , pb->usbStatus ) );
  1573.         pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1574.         if ( pPrinterPB->readDrvr.ctl != NULL )
  1575.             CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->readDrvr.ctl ); 
  1576.         pPrinterPB->readDrvr.ctl = NULL;
  1577.     }
  1578. }
  1579.  
  1580.  
  1581. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1582.     Name:        WriteCompletion
  1583.  
  1584.     Input Parameters:    
  1585.         pb                        USB parameter block
  1586.         
  1587.     Output Parameters:
  1588.         <none>
  1589.  
  1590.     Description:
  1591.         USB write requests complete here.
  1592.         We dequeue the MacOS DRVR write requests
  1593.  
  1594.         when breaking up transactions we use ioActCount to determine how much remains 
  1595.                 of the original request and where the next request begins
  1596.         if we've failed with a USB error
  1597.             usbActCount indicates how much data has been transferred with the current request
  1598.             and if the retry count hasn't been exceeded
  1599.                 we proceed as if we'd just requested that much in this transactions
  1600.         note the retry count is cumulative for the original client request
  1601.             not for each usb transaction
  1602.  
  1603.     Change History:
  1604.         10 Aug 1998,    oja:        set writeDrvr.ctl to NULL when finished
  1605.         28 Jul 1998,    oja:        breakdown transactions into MAX_USB_TRANSFER_SIZE
  1606.         27 Jul 1998,    oja:        lock memory (UIM doesn't do this properly)
  1607.         20 Jul 1998,    oja:        retry transactions
  1608.         16 Jul 1998,    oja:        clear write pipe, not control pipe
  1609.         28 Feb 1998,    oja:        Original version.
  1610. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1611. static void
  1612. WriteCompletion(USBPB *pb)
  1613. {
  1614.     //    call the user completion routine
  1615.     struct usbPrinterPBStruct
  1616.                     *pPrinterPB =  (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1617.     IOParamPtr     clientParam = pPrinterPB->writeDrvr.pb;
  1618.     OSStatus        err = pb->usbStatus;
  1619.  
  1620. #if MACSBUG_ON_WRITE_COMPLETE
  1621.     Str255    text;
  1622.     sprintf( (char *)text, " PrinterClass Write Complete(%d): %d", pb->usbStatus, pb->usbActCount );
  1623.     text[0] = cstrlen((char *)text); // c2pstr
  1624.     DebugStr( text );
  1625. #endif
  1626.  
  1627.     //    update the amount of data actually transferred
  1628.     clientParam->ioActCount += pb->usbActCount;
  1629.  
  1630.     switch( pb->usbStatus )
  1631.     {
  1632.         //
  1633.         //    only retry low level hardware problems
  1634.         //        note: abort transactions will end up here as well
  1635.         //
  1636.     case kUSBLinkErr:
  1637.     case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  1638.     case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  1639.     case kUSBDataToggleErr:                        /*  Pipe stall, Bad data toggle */
  1640.     case kUSBNotRespondingErr:                    /*  Pipe stall, No device, device hung */
  1641.     case kUSBPIDCheckErr:                        /*  Pipe stall, PID CRC error */
  1642.     case kUSBWrongPIDErr:                        /*  Pipe stall, Bad or wrong PID */
  1643.         if (  --(pPrinterPB->writeRetryCount) > 0 ) 
  1644.         {
  1645.             // we got an error, and we still want to retry, clear any stalls
  1646.             USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "WriteCompletion retry" , pb->usbStatus );
  1647.             USBClearPipeStallByReference(pPrinterPB->writePipe);
  1648.             pb->usbStatus = noErr;
  1649.         }
  1650.         break;
  1651.     case kUSBAbortedError:                        /* user cancel, or hot unplug */
  1652.         USBClearPipeStallByReference(pPrinterPB->writePipe);
  1653.         USBClearPipeStallByReference(pPrinterPB->device);
  1654.         break;
  1655.         //
  1656.         //    any other error will be reported to the client
  1657.         //
  1658.     default:
  1659.     case noErr:
  1660.         break;
  1661.     }
  1662.  
  1663.     if ( pb->usbStatus == noErr && clientParam->ioActCount < clientParam->ioReqCount )
  1664.     {
  1665.         //
  1666.         //    haven't finish the client's request
  1667.         //        update the pointers and start another bulkOut transaction
  1668.         //
  1669. #if LOCK_MEMORY
  1670.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1671.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion UnlockMem failed" ) );
  1672. #endif
  1673.         pb->usbBuffer = clientParam->ioBuffer + clientParam->ioActCount;
  1674.         pb->usbReqCount = clientParam->ioReqCount - clientParam->ioActCount;
  1675. #if MAX_USB_TRANSFER_SIZE
  1676.         if ( pb->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1677.             pb->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1678. #endif
  1679. #if DOUBLE_BUFFER
  1680.         //
  1681.         //    make sure we have enough room in our buffer
  1682.         //    then copy the user data into our page aligned buffer
  1683.         //
  1684.         if ( pb->usbReqCount > pPrinterPB->pageWriteAlignedBufferSize )
  1685.             pb->usbReqCount = pPrinterPB->pageWriteAlignedBufferSize;
  1686.         BlockCopy( pb->usbBuffer, pPrinterPB->pageWriteAlignedBuffer, pb->usbReqCount );
  1687.         pb->usbBuffer = pPrinterPB->pageWriteAlignedBuffer;
  1688. #endif
  1689. #if LOCK_MEMORY
  1690.         err = LockMemory( pb->usbBuffer, pb->usbReqCount );
  1691.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion LockMem failed" ) );
  1692.         if ( err == noErr )
  1693. #endif
  1694.             err = USBBulkWrite( pb );
  1695.         if ( immediateError(err) )
  1696.         {
  1697.             USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "WriteCompletion finish immed err" , err );
  1698.  
  1699.             pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1700.             if ( pPrinterPB->writeDrvr.ctl != NULL )
  1701.                 CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, err, clientParam, pPrinterPB->writeDrvr.ctl ); 
  1702.             pPrinterPB->writeDrvr.ctl = NULL;
  1703.         }
  1704.     }
  1705.     else
  1706.     {
  1707.         //
  1708.         //        either we have an error which we're not retrying
  1709.         //            or we successfully completed
  1710.         //
  1711. #if LOCK_MEMORY
  1712.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1713.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion concluded UnlockMem failed" ) );
  1714. #endif
  1715.         IF_DEBUG( if (pb->usbStatus != noErr) USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "WriteCompletion Error" , pb->usbStatus ) );
  1716.         pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1717.         if ( pPrinterPB->writeDrvr.ctl != NULL )
  1718.             CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->writeDrvr.ctl ); 
  1719.         pPrinterPB->writeDrvr.ctl = NULL;
  1720.     }
  1721. }
  1722.  
  1723. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1724.     Name:        QueueRead
  1725.  
  1726.     Input Parameters:    
  1727.         pb                        MacOS device manager parameter block
  1728.         ctl                    device manager dCtl block
  1729.         pPrinterPB            current printing device class's storage
  1730.         
  1731.     Output Parameters:
  1732.         <none>
  1733.  
  1734.     Description:
  1735.         MacOS DRVR read requests are re-queued here to the USB
  1736.         Since we only allow one read request pending at a time, we're able
  1737.         to use the USB refCon to point to our class driver's storage.
  1738.  
  1739.     Change History:
  1740.         28 Feb 1998,    oja:        Original version.
  1741. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1742. void
  1743. QueueRead( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  1744. {    
  1745.     OSStatus    err;
  1746.     USBPB        *usbprint = &pPrinterPB->in;
  1747.     
  1748. #if MACSBUG_ON_READ
  1749.     Str255    text;
  1750.  
  1751.     sprintf( (char *)text, " PrinterClass Read: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1752.     text[0] = cstrlen((char *)text); // c2pstr
  1753.     USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
  1754.     DebugStr( text );
  1755. #endif
  1756.  
  1757.     pb->ioActCount = 0;        // nothing transfered yet
  1758.     if ( pPrinterPB->terminating )
  1759.         pb->ioResult = abortErr;
  1760.     else
  1761.     {
  1762.  
  1763.         pPrinterPB->readRetryCount = 5;
  1764.         pPrinterPB->readDrvr.pb= pb;
  1765.         pPrinterPB->readDrvr.ctl = ctl;
  1766.         if ( pPrinterPB->readPipe != NULL )
  1767.         {
  1768.             SetNullUSBParamBlock( pPrinterPB->readPipe,  usbprint );
  1769.             usbprint->usbBuffer = pb->ioBuffer;
  1770.             usbprint->usbReqCount = pb->ioReqCount;
  1771.  
  1772. #if MAX_USB_TRANSFER_SIZE
  1773.             //
  1774.             //    the completion routine will queue another BulkWrite until we exhaust the data
  1775.             //        or there is an error which can't be retried
  1776.             //
  1777.             if ( usbprint->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1778.                 usbprint->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1779. #endif
  1780. #if DOUBLE_BUFFER
  1781.             //
  1782.             //    make sure we have enough room in our buffer
  1783.             //    then copy the user data into our page aligned buffer
  1784.             //
  1785.             if ( usbprint->usbReqCount > pPrinterPB->pageReadAlignedBufferSize )
  1786.                 usbprint->usbReqCount = pPrinterPB->pageReadAlignedBufferSize;
  1787.             usbprint->usbBuffer = pPrinterPB->pageReadAlignedBuffer;
  1788. #endif
  1789.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  1790.         
  1791.             usbprint->usbCompletion = (USBCompletion) ReadCompletion;
  1792.             
  1793.             pb->ioResult = ioInProgress;
  1794.             err = USBBulkRead( usbprint );
  1795.             if ( immediateError(err) )
  1796.             {
  1797.                 IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
  1798.                 pb->ioResult = err;
  1799.             }
  1800.         }
  1801.         else
  1802.         {
  1803.             USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "Read to unopened pipe" , usbprint->usbStatus ) ;
  1804.             pb->ioResult = abortErr;
  1805.         }
  1806.     }
  1807. }
  1808.  
  1809. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1810.     Name:        QueueWrite
  1811.  
  1812.     Input Parameters:    
  1813.         pb                        MacOS device manager parameter block
  1814.         ctl                    device manager dCtl block
  1815.         pPrinterPB            current printing device class's storage
  1816.         
  1817.     Output Parameters:
  1818.         <none>
  1819.  
  1820.     Description:
  1821.         MacOS DRVR write requests are re-queued here to the USB
  1822.         Since we only allow one read request pending at a time, we're able
  1823.         to use the USB refCon to point to our class driver's storage.
  1824.  
  1825.     Change History:
  1826.         28 Feb 1998,    oja:        Original version.
  1827. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1828. void
  1829. QueueWrite( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  1830. {
  1831.     OSStatus    err;
  1832.     USBPB        *usbprint = &pPrinterPB->out;
  1833. #if VIRTUAL_MEMORY_CHECK
  1834.     //
  1835.     //    dump the VM table
  1836.     //
  1837.     Str255                        text;
  1838.     LogicalToPhysicalTable    *vmTable;
  1839.     MemoryBlock                    *physical;
  1840.     unsigned long                vmCount,
  1841.                                     vmEntry,
  1842.                                     vmTblLength;
  1843. #endif
  1844.  
  1845. #if MACSBUG_ON_WRITE
  1846.     Str255    text;
  1847.     sprintf( (char *)text, " PrinterClass Write: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1848.     text[0] = cstrlen((char *)text); // c2pstr
  1849.     USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
  1850.     DebugStr( text );
  1851. #endif
  1852.  
  1853. #if VIRTUAL_MEMORY_CHECK
  1854.     //
  1855.     //    this check current won't compile without runtime error: need to lock memory, but lock has moved
  1856.     //
  1857.     sprintf( (char *)text, " PrinterClass Write: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1858.     text[0] = cstrlen((char *)text); // c2pstr
  1859.     USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
  1860.     
  1861.     vmCount = 127;
  1862.     vmTblLength = (vmCount+1)*sizeof(MemoryBlock);
  1863.     vmTable = (LogicalToPhysicalTable *) NewPtrSys( vmTblLength );
  1864.     LockMemory( vmTable, vmTblLength );
  1865.     LockMemory( &vmCount, sizeof(unsigned long) );
  1866.     vmTable->logical.address = pb->ioBuffer;
  1867.     vmTable->logical.count = pb->ioReqCount;
  1868.     err = GetPhysical( vmTable, &vmCount );
  1869.     
  1870.     if ( err == noErr )
  1871.     {
  1872.         for ( vmEntry = 0, physical = &vmTable->physical[0]; vmEntry < vmCount; ++vmEntry , ++physical)
  1873.         {
  1874.             sprintf( (char *)text, " PrinterClass Write: VM @%08x (%d)", physical->address, physical->count );
  1875.             text[0] = cstrlen((char *)text); // c2pstr
  1876.             USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
  1877.         }
  1878.     }
  1879.     UnlockMemory( vmTable, vmTblLength );
  1880.     UnlockMemory( &vmCount, sizeof(unsigned long) );
  1881. #endif
  1882.     pb->ioActCount = 0;        // nothing transfered yet
  1883.  
  1884.  
  1885.     usbprint->usbStatus = noErr;    // forget about abort and things from previous writes
  1886.     if ( pPrinterPB->terminating )
  1887.         pb->ioResult = abortErr;
  1888.     else
  1889.     {
  1890.         pPrinterPB->writeRetryCount = 5;
  1891.         pPrinterPB->writeDrvr.pb = pb;
  1892.         pPrinterPB->writeDrvr.ctl = ctl;
  1893.         if ( pPrinterPB->writePipe != NULL )
  1894.         {
  1895.             SetNullUSBParamBlock( pPrinterPB->writePipe,  usbprint );
  1896.             usbprint->usbBuffer = pb->ioBuffer;
  1897.             usbprint->usbReqCount = pb->ioReqCount;
  1898. #if MAX_USB_TRANSFER_SIZE
  1899.             //
  1900.             //    the completion routine will queue another BulkWrite until we exhaust the data
  1901.             //        or there is an error which can't be retried
  1902.             //
  1903.             if ( usbprint->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1904.                 usbprint->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1905. #endif
  1906. #if DOUBLE_BUFFER
  1907.             //
  1908.             //    make sure we have enough room in our buffer
  1909.             //    then copy the user data into our page aligned buffer
  1910.             //
  1911.             if ( usbprint->usbReqCount > pPrinterPB->pageWriteAlignedBufferSize )
  1912.                 usbprint->usbReqCount = pPrinterPB->pageWriteAlignedBufferSize;
  1913.             BlockCopy( usbprint->usbBuffer, pPrinterPB->pageWriteAlignedBuffer, usbprint->usbReqCount );
  1914.             usbprint->usbBuffer = pPrinterPB->pageWriteAlignedBuffer;
  1915. #endif
  1916.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  1917.         
  1918.             usbprint->usbCompletion = (USBCompletion) WriteCompletion;
  1919.              
  1920.             pb->ioResult = ioInProgress;
  1921.     
  1922. #if LOCK_MEMORY
  1923.             err = LockMemory( usbprint->usbBuffer, usbprint->usbReqCount );
  1924.             IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass QueueWrite LockMem failed" ) );
  1925.             if ( err == noErr )
  1926. #endif
  1927.                 err = USBBulkWrite( usbprint );
  1928.             if ( immediateError(err) )
  1929.             {
  1930.                 IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
  1931.                 pb->ioResult = err;
  1932.             }
  1933.             //
  1934.             //    note our logging is one write for each the client request
  1935.             //        not one write for each usb transaction
  1936.             //
  1937.             LOGGING( fwrite( pb->ioBuffer, sizeof(char), pb->ioReqCount, logfile ) );
  1938.         }
  1939.         else
  1940.         {
  1941.             USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "Write to unopened pipe" , usbprint->usbStatus );
  1942.             pb->ioResult = abortErr;
  1943.         }
  1944.     }
  1945. }
  1946.  
  1947.  
  1948. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1949.     Name:        Abort
  1950.  
  1951.     Input Parameters:    
  1952.         refNum            DRVR refnum
  1953.         pPrinterPB        current printing device class's storage
  1954.  
  1955.     Output Parameters:
  1956.         
  1957.     Description:
  1958.         Asynchronous completion.
  1959.         Note: USBAbortPipeByReference can leave the data toggle in the wrong state.
  1960.                 We need to abort both pipes, and then the client must soft reset the printer
  1961.                 to get the printer's data toggles correct.
  1962.         We prematurely call completion routines for active i/o so that CloseDriverSync
  1963.             will not hang the system after an abort, including hot unplug. This works out okay,
  1964.             since the request will be dequeued now, and when the i/o actually terminates
  1965.             the system will be called with an invalid queue element and then reject this second
  1966.             attempt to dequeue the i/o.
  1967.  
  1968.     Change History:
  1969.          4 Aug 1998,    oja:        abort both pipes, call completion routines
  1970.         28 Feb 1998,    oja:        Original version.
  1971. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1972. OSStatus
  1973. Abort( DriverRefNum refNum, struct usbPrinterPBStruct *pPrinterPB )
  1974. {
  1975.     OSStatus        err = noErr;
  1976.  
  1977.  
  1978.     refNum = 0;    // unused
  1979.     //
  1980.     //    if there's any pending io this will call the completion routine
  1981.     //
  1982.     err = USBAbortPipeByReference( pPrinterPB->writePipe );
  1983.     err = USBAbortPipeByReference( pPrinterPB->readPipe );
  1984.  
  1985.     if ( pPrinterPB->out.usbCompletion != (USBCompletion) NULL )
  1986.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, abortErr, pPrinterPB->writeDrvr.pb, pPrinterPB->writeDrvr.ctl ); 
  1987.     if ( pPrinterPB->in.usbCompletion != (USBCompletion) NULL )
  1988.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, abortErr, pPrinterPB->readDrvr.pb, pPrinterPB->readDrvr.ctl ); 
  1989.     return err;
  1990. }
  1991.  
  1992.  
  1993. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1994.     Name:        CompletionProc
  1995.  
  1996.     Input Parameters:    
  1997.         pb                    USB param block ptr
  1998.     
  1999.     Output Parameters:
  2000.         
  2001.     Description:
  2002.         Asynchronous completion routine for DRVR requests.
  2003.  
  2004.     Change History:
  2005.         10 Aug 1998,    oja:        if error, do not set clientParam's ioResult
  2006.                                             explicitly (wait for JIODone)
  2007.         11 Jun 1998,    oja:        Original version.
  2008. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2009. static void 
  2010. CompletionProc(USBPB *pb)
  2011. {
  2012.     //    call the user completion routine
  2013.     struct usbPrinterPBStruct
  2014.                     *pPrinterPB = (struct usbPrinterPBStruct    *) pb->usbRefcon;
  2015.     IOParamPtr     clientParam = pPrinterPB->statusDrvr.pb;
  2016.  
  2017.     clientParam->ioActCount = pb->usbActCount;
  2018.  
  2019.     if ( pb->usbStatus != noErr ) 
  2020.     {
  2021.         USBClearPipeStallByReference(pb->usbReference);  // we got an error, try to clear any stalls
  2022.  
  2023.         IF_DEBUG( USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "CompletionProc Error" , pb->usbStatus ) );
  2024.         IF_DEBUG( USBExpertStatus(pPrinterPB->device, USBStatusStr(pb->usbStatus, kPString) , pb->usbStatus ) );
  2025.     }
  2026.  
  2027.     pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  2028.     if ( pPrinterPB->statusDrvr.ctl != NULL )
  2029.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->statusDrvr.ctl ); 
  2030. }
  2031.  
  2032. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2033.     Name:        CentronicsStatus
  2034.  
  2035.     Input Parameters:    
  2036.         pb                        MacOS device manager parameter block
  2037.         ctl                    device manager dCtl block
  2038.         pPrinterPB            current printing device class's storage
  2039.  
  2040.     Output Parameters:
  2041.         pStatusByte        
  2042.         
  2043.     Description:
  2044.         setup the device request for a USB printer class request one byte status.
  2045.  
  2046.     Change History:
  2047.         29 Jun 1998,    oja:        called from StatusControlRequests, change params
  2048.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  2049.         11 Jun 1998,    oja:        Original version.
  2050. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2051. static void
  2052. CentronicsStatus( USBPB *usbprint, Ptr buffer, short interfaceNumber )
  2053. {
  2054.     usbprint->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  2055.  
  2056.     usbprint->usbBRequest = kUSBPrintClassGetCentronicsStatus;
  2057.     usbprint->usbWValue = 0;
  2058.     usbprint->usbWIndex = interfaceNumber;
  2059.  
  2060.     usbprint->usbReqCount = 1;
  2061.     usbprint->usbBuffer = buffer;
  2062. }
  2063.  
  2064. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2065.     Name:        SoftReset
  2066.  
  2067.     Input Parameters:    
  2068.         usbprint                USB param block
  2069.         interfaceNumber
  2070.  
  2071.     Output Parameters:
  2072.         
  2073.     Description:
  2074.         Setup the device request for a USB printer class request soft reset.
  2075.  
  2076.     Change History:
  2077.         29 Jun 1998,    oja:        called from StatusControlRequests, change params
  2078.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  2079.         11 Jun 1998,    oja:        Original version.
  2080. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2081. void
  2082. SoftReset( USBPB *usbprint, short interfaceNumber )
  2083. {
  2084.     usbprint->usbBMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBOther);
  2085.  
  2086.     usbprint->usbBRequest = kUSBPrintClassSoftReset;
  2087.     usbprint->usbWValue = 0;
  2088.     usbprint->usbWIndex = interfaceNumber;
  2089.  
  2090.     usbprint->usbReqCount = 0;
  2091.     usbprint->usbBuffer = NULL;
  2092.  
  2093. }
  2094.  
  2095. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2096.     Name:        CapabilityRequest
  2097.  
  2098.     Input Parameters:    
  2099.         usbprint            USB parameter block
  2100.         p                    result pointer
  2101.         length            amount of data allocated
  2102.         config
  2103.         interfaceNum
  2104.         alternateSetting
  2105.         
  2106.  
  2107.     Output Parameters:
  2108.         p                    result pointer
  2109.         length            amount of data allocated
  2110.         
  2111.     Description:
  2112.         setup the device request for a USB printer class request 1284 id string.
  2113.  
  2114.     Change History:
  2115.         29 Jun 1998,    oja:        called from StatusControlRequests, change params
  2116.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  2117.         11 Jun 1998,    oja:        Original version.
  2118. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2119. void
  2120. CapabilityRequest( USBPB *pb, Ptr p, long length, short configValue, short interfaceNumber, short alternateSetting  )
  2121. {
  2122.  
  2123.     pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  2124.  
  2125.     pb->usbBRequest = kUSBPrintClassGetDeviceID;
  2126.     pb->usbWValue = configValue;        // configuration
  2127.     pb->usbWIndex = (interfaceNumber<<8) | alternateSetting;
  2128.  
  2129.     pb->usbReqCount = length;
  2130.     pb->usbBuffer = p;
  2131.  
  2132. }
  2133.  
  2134. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2135.     Name:        StatusControlRequests
  2136.  
  2137.     Input Parameters:    
  2138.         pb                        MacOS device manager parameter block
  2139.         ctl                    device manager dCtl block
  2140.         pPrinterPB            current printing device class's storage
  2141.  
  2142.     Output Parameters:
  2143.         
  2144.     Description:
  2145.         Asynchronous completion.
  2146.  
  2147.     Change History:
  2148.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  2149.         11 Jun 1998,    oja:        Original version.
  2150. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2151.  
  2152. void
  2153. ControlStatusRequests( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  2154. {
  2155.  
  2156.     //
  2157.     //    queue a transaction to retrieve the centronics status
  2158.     //
  2159.     OSStatus        err;
  2160.     USBPB            *usbprint = &pPrinterPB->pb;
  2161.     Boolean        dosomething = false;
  2162.     
  2163. #if DEBUG
  2164.     Str255        text;
  2165.  
  2166.     sprintf( (char *)text, " PrinterClass ControlStatus: %d", ((CntrlParam *) pb)->csCode );
  2167.     text[0] = cstrlen((char *)text); // c2pstr
  2168.     USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
  2169. #endif
  2170.  
  2171.     switch( ((CntrlParam *) pb)->csCode )
  2172.     {
  2173.     case kDrvrCentronicsStatus:
  2174.         dosomething = true;
  2175.         CentronicsStatus( usbprint,  *((Ptr *)((CntrlParam *) pb)->csParam), (pPrinterPB->interface)->interfaceNumber );
  2176.         break;
  2177.     case kDrvr1284IdString:
  2178.         dosomething = true;
  2179.         CapabilityRequest( usbprint,
  2180.                                 *((Ptr *)((CntrlParam *) pb)->csParam),
  2181.                                 *((long *) &((CntrlParam *) pb)->csParam[4]),
  2182.                                 (pPrinterPB->config)->configValue,        // configuration
  2183.                                 (pPrinterPB->interface)->interfaceNumber,
  2184.                                 (pPrinterPB->interface)->alternateSetting );
  2185.         break;
  2186.     case kDrvrSoftReset:
  2187.         dosomething = true;
  2188.         SoftReset( usbprint, (pPrinterPB->interface)->interfaceNumber );
  2189.         break;
  2190.     default:
  2191.         break;
  2192.     }
  2193.  
  2194.     if ( !dosomething )
  2195.         pb->ioResult = paramErr;
  2196.     else
  2197.     {
  2198.         SetNullUSBParamBlock(pPrinterPB->device,  usbprint );
  2199.         usbprint->usbCompletion = (USBCompletion)CompletionProc;
  2200.         usbprint->usbRefcon = (unsigned long) pPrinterPB;
  2201.     
  2202.         pb->ioResult = ioInProgress;
  2203.         pPrinterPB->statusDrvr.pb = pb;
  2204.         pPrinterPB->statusDrvr.ctl = ctl;
  2205.     
  2206.         err = USBDeviceRequest(usbprint);
  2207.         if(immediateError(err))
  2208.         {
  2209.             USBExpertFatalError(usbprint->usbReference, err, "\p" kStrPrinterClass "StatusControlRequests", 0);
  2210.             pb->ioResult = err;
  2211.         }
  2212.     }
  2213. }
  2214.  
  2215.  
  2216. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2217.     Name:        PrinterDeviceCompletionProc
  2218.  
  2219.     Input Parameters:    
  2220.         pb                refCon tells which state we're completing
  2221.  
  2222.     Output Parameters:
  2223.         <none>
  2224.         
  2225.     Description:
  2226.         Complete asynch transactions initiated by PrinterDeviceInitiateTransaction.
  2227.  
  2228.     Change History:
  2229.         17 Aug 1998,    oja:        don't retry high level errors (support hot unplug of root hub)
  2230.         20 Jul 1998,    oja:        clear pipe stall before retrying
  2231.         15 May 1998,    oja:        added missing break for GetCapabilityString
  2232.                                         reworked GetFullConfiguration to properly handle case
  2233.                                             where there's only one interface
  2234.         26 Mar 1998,    oja:        set info 1 to DEBUG StateStr
  2235.                                         (distinguishes completion from initiate)
  2236.         28 Feb 1998,    oja:        Original version.
  2237. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2238.  
  2239. static void 
  2240. PrinterDeviceCompletionProc(USBPB *pb)
  2241. {
  2242.     register struct usbPrinterPBStruct *pPrinterPB;
  2243.     int                                            numInterface;
  2244.  
  2245.     pPrinterPB = (struct usbPrinterPBStruct *)(pb);
  2246.     pPrinterPB->transDepth--; 
  2247.     if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
  2248.     {
  2249.         USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "CompletionProc Illegal Transaction Depth", pPrinterPB->transDepth );
  2250.     }
  2251.  
  2252.     IF_DEBUG( USBExpertStatus(pPrinterPB->device, StateStr(pPrinterPB->pb.usbRefcon, kPString) , 1 ) );
  2253.  
  2254.     switch( pPrinterPB->pb.usbStatus )
  2255.     {
  2256.     case kUSBPending:
  2257.     case noErr:
  2258.         pPrinterPB->pb.usbRefcon &= ~kRetryTransaction;
  2259.         pPrinterPB->retryCount = kPrinterRetryCount;
  2260.         break;
  2261.     case kUSBLinkErr:
  2262.     case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  2263.     case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  2264.     case kUSBDataToggleErr:                        /*  Pipe stall, Bad data toggle */
  2265.     case kUSBNotRespondingErr:                    /*  Pipe stall, No device, device hung */
  2266.     case kUSBPIDCheckErr:                        /*  Pipe stall, PID CRC error */
  2267.     case kUSBWrongPIDErr:                        /*  Pipe stall, Bad or wrong PID */
  2268.     
  2269.         USBClearPipeStallByReference(pPrinterPB->device);  // we got an error, try to clear any stalls
  2270.         USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "    retry", pPrinterPB->pb.usbStatus);
  2271.  
  2272.         pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kAsyncTransaction + kReturnFromDriver);
  2273.         pPrinterPB->pb.usbRefcon |= kRetryTransaction;
  2274.         pPrinterPB->retryCount--;
  2275.         if (!pPrinterPB->retryCount)
  2276.         {
  2277.             USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "Retry failed", pPrinterPB->pb.usbRefcon & ~kRetryTransaction);
  2278.             pPrinterPB->pb.usbRefcon = kUndefined | kReturnFromDriver;
  2279.             return;
  2280.         } else {
  2281.             pPrinterPB->pb.usbStatus = noErr; // let's retry one more time
  2282.         }
  2283.         break;
  2284.     default:
  2285.         //    don't retry
  2286.         pPrinterPB->pb.usbCompletion    = (USBCompletion) NULL;
  2287.         pPrinterPB->pb.usbRefcon = kReturnFromDriver;
  2288.         break;
  2289.     }
  2290.  
  2291.     if (pPrinterPB->pb.usbRefcon & kTransactionPending)             
  2292.     {            
  2293.         int    length;
  2294.     
  2295.         //
  2296.         //    advance to the next state
  2297.         //
  2298.         pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kAsyncTransaction + kReturnFromDriver);
  2299.         switch(pPrinterPB->pb.usbRefcon)
  2300.         {
  2301.             case kGetConfigurationDescriptor:
  2302.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2303.                 {
  2304.                     pPrinterPB->pb.usbRefcon = kGetFullConfiguration;    
  2305.                 }
  2306.                 break;
  2307.                 
  2308.             case kGetFullConfiguration:
  2309.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2310.                 {
  2311.                     pPrinterPB->interface = FindInterface( pPrinterPB->config, kUSBPrintClassProtocolBidirectional );
  2312.                     if ( pPrinterPB->interface == NULL )
  2313.                     {
  2314.                         pPrinterPB->interface = FindInterface( pPrinterPB->config, kUSBPrintClassProtocolUnidirectional );
  2315.                         if ( pPrinterPB->interface == NULL )
  2316.                             USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "Can't find protocol", 0);
  2317.                     }
  2318.                     if ( pPrinterPB->interface != NULL )
  2319.                         pPrinterPB->interfaceOffset =  (char *) pPrinterPB->interface - (char *) pPrinterPB->config;
  2320.  
  2321.                     //
  2322.                     // if there's only one interface (or alternate) supported
  2323.                     //        skip the attempt to assign the interface
  2324.                     //
  2325.                     numInterface = CountInterface( pPrinterPB->config, kUSBPrintClass, kUSBPrintSubClass );
  2326.                     if ( numInterface <= 1 )
  2327.                         pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  2328.                     else
  2329.                         pPrinterPB->pb.usbRefcon = kSetInterface;
  2330.                 }
  2331.                 break;
  2332.                 
  2333.             case kSetInterface:
  2334.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2335.                 {
  2336.                     SetNullUSBParamBlock(pPrinterPB->device,  pb );
  2337.                     pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  2338.                 }
  2339.                 break;
  2340.                 
  2341.             case kGetCapabilityString:
  2342.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2343.                 {
  2344.                     //
  2345.                     //    In the short term (fall '98) several vendors are planning on shipping 
  2346.                     //        devices with a parallel port and using the Lucent USS-720 USB-to-parallel hardware.
  2347.                     //    Unfortunately this isn't an ideal solution from the USB perspective:
  2348.                     //        users can leave the printer off while the cable responds that there's
  2349.                     //        a printer connected. Then we have no way of using the DEVICE_ID
  2350.                     //        string to tag the printer and register it.
  2351.                     //    To alleviate this situation, we repeatedly poll the USS-720 if the DEVICE_ID
  2352.                     //        string is null. Every few seconds we'll retry this state.
  2353.                     //    At some point the user wants to print and switches on the printer. The class
  2354.                     //    driver then picks up from here and registers the device properly.
  2355.                     //
  2356.                     length = pPrinterPB->capabilityString[1] | (pPrinterPB->capabilityString[0] << 8);
  2357.                     if ( IsLucentCable( &pPrinterPB->desc ) && pPrinterPB->pb.usbActCount == 0 )
  2358.                         pPrinterPB->pb.usbRefcon = kDelayGetCapability;
  2359.                     else
  2360.                         pPrinterPB->pb.usbRefcon = kGetInterface;
  2361.                 }
  2362.                 else if ( pPrinterPB->pb.usbStatus == kUSBOverRunErr )
  2363.                 {
  2364.                     //
  2365.                     //    if we've haven't managed to read the whole capability string
  2366.                     //        we need to allocate memory and read it in by initiating kGetFullCapabilityString
  2367.                     //
  2368.                     length = pPrinterPB->capabilityString[1] | (pPrinterPB->capabilityString[0] << 8);
  2369.  
  2370.                     if ( length > sizeof(pPrinterPB->capability) &&
  2371.                             pPrinterPB->pb.usbRefcon == kGetCapabilityString )
  2372.                         pPrinterPB->pb.usbRefcon = kGetFullCapabilityString;
  2373.                 }
  2374.                 break;
  2375.             case kDelayGetCapability:
  2376.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2377.                     pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  2378.                 break;
  2379.             case kGetFullCapabilityString:
  2380.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2381.                     pPrinterPB->pb.usbRefcon = kGetInterface;
  2382.                 break;
  2383.             case kGetInterface:
  2384.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2385.                     pPrinterPB->pb.usbRefcon = kOpenBulkOutPipe;
  2386.                 break;
  2387.             case kOpenBulkOutPipe:
  2388.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2389.                 {
  2390.                     pPrinterPB->writePipe = pPrinterPB->pb.usbReference; // remember the ref
  2391.                     pPrinterPB->out = pPrinterPB->pb;
  2392.                     pPrinterPB->out.usbCompletion =  (USBCompletion) NULL;    // for finalize
  2393.  
  2394.                     if ( pPrinterPB->interface->interfaceProtocol == kUSBPrintClassProtocolBidirectional )
  2395.                         pPrinterPB->pb.usbRefcon = kOpenBulkInPipe;
  2396.                     else
  2397.                         pPrinterPB->pb.usbRefcon = kEnterNameRegistry;
  2398.                 }
  2399.                 break;
  2400.             case kOpenBulkInPipe:
  2401.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2402.                 {
  2403.                     pPrinterPB->readPipe = pPrinterPB->pb.usbReference;
  2404.                     pPrinterPB->in = pPrinterPB->pb;
  2405.                     pPrinterPB->in.usbCompletion =  (USBCompletion) NULL;    // for finalize
  2406.  
  2407.                     pPrinterPB->pb.usbRefcon = kEnterNameRegistry;
  2408.                 }
  2409.                 break;
  2410.             case kEnterNameRegistry:
  2411.                 //
  2412.                 //    note: this state isn't reachable
  2413.                 //
  2414.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2415.                 {
  2416.                     pPrinterPB->pb.usbRefcon = kGetCentronicsStatus;
  2417.                 }
  2418.                 break;
  2419.             case kGetCentronicsStatus:
  2420.                 //
  2421.                 //    if InitiateTransaction fell through on it's kEnterNameRegistry case we'll end up here
  2422.                 //
  2423.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2424.                 {
  2425. #if DEBUG
  2426.                     Str255    text, te;
  2427.                     hexstr( sizeof(char), &pPrinterPB->centronics.b, (char *) te );
  2428.                     sprintf( (char *)text, " PrinterClass Status: %s", te );
  2429.                     text[0] = cstrlen((char *)text); // c2pstr
  2430.                     USBExpertStatus(pPrinterPB->device, text, pb->usbStatus );
  2431. #endif
  2432. #if DEBUG
  2433.                     if ( !pPrinterPB->centronics.status.notError )
  2434.                     {
  2435.                         USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "Error at printer", pPrinterPB->pb.usbStatus);
  2436.                     }
  2437.                     if ( pPrinterPB->centronics.status.paperError )
  2438.                     {
  2439.                         USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "Check paper", pPrinterPB->pb.usbStatus);
  2440.                     }
  2441.                     if ( !pPrinterPB->centronics.status.select )
  2442.                     {
  2443.                         USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "printer offline", pPrinterPB->pb.usbStatus);
  2444.                     }
  2445. #endif
  2446.                     pPrinterPB->pb.usbRefcon = kDelayGetCentronicsStatus;
  2447.                 }
  2448.                 break;
  2449.             case kDelayGetCentronicsStatus:
  2450.                 //
  2451.                 //    loop around continually getting status
  2452.                 //
  2453.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2454.                 {
  2455.                     pPrinterPB->pb.usbRefcon = kGetCentronicsStatus;
  2456.                 }
  2457.                 break;
  2458.             case kNilCompletion:
  2459.             default:
  2460.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2461.                     pPrinterPB->pb.usbRefcon = kUndefined | kReturnFromDriver;
  2462.                 break;
  2463.         }
  2464.     }
  2465.  
  2466.     if ( pPrinterPB->terminating )
  2467.     {
  2468.         //    if we've been hot unplugged
  2469.         //        don't startup any new transactions
  2470.         //     allow PrintDriverFinalize to continue
  2471.         pPrinterPB->pb.usbCompletion    = (USBCompletion) NULL;
  2472.         pPrinterPB->pb.usbRefcon = kReturnFromDriver;
  2473.     }
  2474.     else if ( pPrinterPB->pb.usbStatus == noErr )
  2475.     {
  2476.         if (!(pPrinterPB->pb.usbRefcon & kReturnFromDriver))
  2477.             PrinterDeviceInitiateTransaction(pb);
  2478.     }
  2479.     else
  2480.     {
  2481.         pPrinterPB->pb.usbCompletion    = (USBCompletion) NULL;
  2482.         pPrinterPB->pb.usbRefcon = kReturnFromDriver;
  2483.         USBExpertFatalError(pPrinterPB->device, pPrinterPB->pb.usbStatus, StateStr(pPrinterPB->pb.usbRefcon, kPString), pPrinterPB->pb.usbRefcon);
  2484.         USBExpertFatalError(pPrinterPB->device, pPrinterPB->pb.usbStatus, USBStatusStr(pPrinterPB->pb.usbStatus, kPString), 0);
  2485.     }
  2486. }
  2487.  
  2488. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2489.     Name:        PrinterDeviceInitiateTransaction
  2490.  
  2491.     Input Parameters:    
  2492.         pb            USB parameter block
  2493.         
  2494.     Output Parameters:
  2495.         
  2496.     Description:
  2497.         Since USB transactions are asynchronous we use the refCon field
  2498.         in the parameter block to implement the following logic via a state machine.
  2499.  
  2500.         Start out by getting the device configuration descriptor
  2501.         If the device has more than one printing interface
  2502.             If a bidirectional interface exists
  2503.                 select it
  2504.             Else
  2505.                 select the (mandatory) unidirectional interface
  2506.         Get the (manadatory) 1284 capability string
  2507.         Open pipes to the BulkOut (and optional BulkIn) endpoints
  2508.         Install read and write drivers in the unit table
  2509.         Using information from the capability string
  2510.             enter the printer in the MacOS name registry.
  2511.         
  2512.  
  2513.     Change History:
  2514.         15 May 1998,    oja:        cleanup error/status messages
  2515.                                         handle setinterface correctly if only one
  2516.                                             interface is available
  2517.         28 Feb 1998,    oja:        Original version.
  2518. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2519. void
  2520. PrinterDeviceInitiateTransaction(USBPB *pb)
  2521. {
  2522.     register struct usbPrinterPBStruct    *pPrinterPB;
  2523.     int                                            length;
  2524.     OSStatus                                        err;
  2525.  
  2526.     pPrinterPB = (struct usbPrinterPBStruct *)(pb);
  2527.     pPrinterPB->transDepth++;
  2528.     if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
  2529.     {
  2530.         USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction illegal transaction depth", 0);
  2531.     }
  2532.     IF_DEBUG( USBExpertStatus( pPrinterPB->device, StateStr(pPrinterPB->pb.usbRefcon, kPString), 0) );     
  2533.  
  2534.     switch(pPrinterPB->pb.usbRefcon & ~kRetryTransaction)
  2535.     {
  2536.         case kGetConfigurationDescriptor:
  2537.             //
  2538.             //    find the device's configuration information
  2539.             //
  2540.             pPrinterPB->config = (USBConfigurationDescriptorPtr) pPrinterPB->configuration;
  2541.             GetConfigurationDescriptor( &pPrinterPB->pb, pPrinterPB->config, sizeof(USBConfigurationDescriptor) );
  2542.             break;
  2543.             
  2544.         case kGetFullConfiguration:
  2545.             //
  2546.             //    not enough room in statically allocated memory for device's configuration
  2547.             //    try again after allocating enough memory
  2548.             //        (memory is released on finalize)
  2549.             length = USBToHostWord( (pPrinterPB->config)->totalLength );
  2550.  
  2551.             pPrinterPB->config = MemAllocatePhysicallyContiguous ((ByteCount)length, true);
  2552.             GetConfigurationDescriptor( &pPrinterPB->pb, pPrinterPB->config, length );
  2553.             break;
  2554.         case kSetInterface:
  2555.             //
  2556.             //    having identified the configuration
  2557.             //        set the device to our prefered interface
  2558.             //
  2559.             SetInterface( &pPrinterPB->pb, pPrinterPB->interface->interfaceNumber, pPrinterPB->interface->alternateSetting );
  2560.             break;
  2561.         case kGetCapabilityString:
  2562.             //
  2563.             //    once the interface (and alternate) is assinged
  2564.             //        we can retreive the 1284 capability string to see what kind of printer
  2565.             //        is attached
  2566.             pPrinterPB->capabilityString = pPrinterPB->capability;
  2567.             GetCapability( pPrinterPB, pPrinterPB->capabilityString, sizeof(pPrinterPB->capability) );
  2568.             break;
  2569.         case kDelayGetCapability:
  2570.             //
  2571.             //    USS-720 USB-parallel cable: couldn't get the capability string because the printer is off
  2572.             //        Delay a few seconds and try again.
  2573.             //        Will succeed when the user turns the printer on.
  2574.             //
  2575.             pPrinterPB->pb.usbReqCount = kUSS720MillisecondDelay;
  2576.             pPrinterPB->pb.usbRefcon |= kTransactionPending | kAsyncTransaction;
  2577.             err = USBDelay(&pPrinterPB->pb);
  2578.             if(immediateError(err))
  2579.             {
  2580.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kDelayGetCapability", 0);
  2581.             }
  2582.             break;
  2583.         case kGetFullCapabilityString:
  2584.             //
  2585.             // the capability string was too long to fit in the statically allocated space
  2586.             // need to release this memory when we finalize our driver
  2587.             //
  2588.             length = pPrinterPB->capability[1] | (pPrinterPB->capability[0]<<8);
  2589.  
  2590.             pPrinterPB->capabilityString = MemAllocatePhysicallyContiguous ((ByteCount)length, true);
  2591.             if ( pPrinterPB->capabilityString )
  2592.                 GetCapability( pPrinterPB, pPrinterPB->capabilityString, length );
  2593.             else
  2594.                 USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "Can't allocate capability", 0);
  2595.             break;
  2596.         case kGetInterface:
  2597.             // failsafe check that we've got the right setup
  2598.             //    it's possible the device didn't respond to our SetInterface
  2599.             GetInterface( &pPrinterPB->pb, &pPrinterPB->whichAltInterface );
  2600.             break;
  2601.         case kOpenBulkOutPipe:
  2602.             //
  2603.             //    open mandatory bulk out pipe
  2604.             //
  2605.             OpenBulkEndpoint( pPrinterPB, kOpenBulkOutPipe );
  2606.             break;
  2607.         case kOpenBulkInPipe:    
  2608.             //
  2609.             //    open optional bulk in pipe
  2610.             //
  2611.             OpenBulkEndpoint( pPrinterPB, kOpenBulkInPipe );
  2612.             break;
  2613.         case kEnterNameRegistry:
  2614.             //
  2615.             //    once we know what device we're dealing with
  2616.             //        open the i/o channel(s) to the device
  2617.             //        and enter it in the name registry
  2618.             //
  2619.             err = InstallDrivers( pPrinterPB );
  2620.             if ( err == noErr )
  2621.                 err = RegisterDevice( pPrinterPB );
  2622.             if ( err != noErr )
  2623.                 USBExpertFatalError(pPrinterPB->device, err, "\p" kStrPrinterClass "RegisterDevice failed", 0);
  2624.  
  2625.             pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;    // Finalize
  2626.              // to stress test usb bus, fallthrough to kGetCentronicsStatus 
  2627.             break;
  2628.  
  2629.         case kGetCentronicsStatus:
  2630.             SetNullUSBParamBlock( pPrinterPB->device, &pPrinterPB->pb );
  2631.  
  2632.             CentronicsStatus( &pPrinterPB->pb,  &pPrinterPB->centronics.b, (pPrinterPB->interface)->interfaceNumber );
  2633.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2634.             pPrinterPB->pb.usbRefcon = kGetCentronicsStatus | kTransactionPending | kAsyncTransaction;
  2635.         
  2636.             err = USBDeviceRequest(&pPrinterPB->pb);
  2637.             if(immediateError(err))
  2638.             {
  2639.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kGetCentronicsStatus", 0);
  2640.             }
  2641.             break;
  2642.         case kDelayGetCentronicsStatus:
  2643.             SetNullUSBParamBlock( pPrinterPB->device, &pPrinterPB->pb );
  2644.  
  2645.             pPrinterPB->pb.usbReqCount = kUSS720StatusMSDelay;
  2646.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2647.             pPrinterPB->pb.usbRefcon |= kTransactionPending | kAsyncTransaction;
  2648.  
  2649.             err = USBDelay(&pPrinterPB->pb);
  2650.             if(immediateError(err))
  2651.             {
  2652.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kDelayGetCentronicsStatus", 0);
  2653.             }
  2654.             break;
  2655.         case kReturnFromDriver:
  2656.             pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;
  2657.             break;
  2658.         default:
  2659.             USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction unknown transaction", 0);
  2660.             pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;
  2661.             pPrinterPB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  2662.             break;
  2663.     }
  2664. }
  2665.  
  2666.  
  2667. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2668.     Name:        PrintDriverEntry
  2669.  
  2670.     Input Parameters:    
  2671.         
  2672.     Output Parameters:
  2673.         
  2674.     Description:
  2675.         This is where the system instantiates a USB printing device.
  2676.  
  2677.         We need to install drivers in the MacOS unitTable, and a reference
  2678.         in the name registry.
  2679.         
  2680.         But the information we need to do this is only available after some 
  2681.         USB transactions have completed. So we initiate here a series of asynchronous
  2682.         USB operations to get that information (by calling the first 
  2683.  
  2684.     Change History:
  2685.         31 Jul 1998,    oja:        page-aligned double buffer i/o
  2686.         30 Jun 1998,    oja:        change CentronicsStatus to ControlStatusRequests
  2687.         28 Feb 1998,    oja:        Original version.
  2688. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2689. void 
  2690. PrintDriverEntry(
  2691.     USBDeviceRef                    device,
  2692.     USBDeviceDescriptorPtr        desc,
  2693.     USBInterfaceDescriptorPtr    pInterface
  2694.     )
  2695. {
  2696.     static Boolean        beenThereDoneThat = false;
  2697.     OSStatus                err;
  2698.     RoutineDescriptor qw = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBWriteProcInfo, QueueWrite);
  2699.     RoutineDescriptor qr = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBReadProcInfo, QueueRead);
  2700.     RoutineDescriptor qa = BUILD_ROUTINE_DESCRIPTOR( uppAbortProcInfo, Abort);
  2701.     RoutineDescriptor qs = BUILD_ROUTINE_DESCRIPTOR( uppControlStatusProcInfo, ControlStatusRequests );
  2702.     
  2703.     if( !beenThereDoneThat)
  2704.     {
  2705.         beenThereDoneThat = true;
  2706.             
  2707.         printerClassRecord.desc = *desc;                /* keep a copy of the device descriptor */
  2708.         if ( pInterface != NULL )
  2709.             printerClassRecord.interface = pInterface;
  2710.     
  2711.         printerClassRecord.device = device;
  2712.         printerClassRecord.transDepth = 0;            /* init Delay Callback Depth */
  2713.     
  2714.         printerClassRecord.inRefNum =  -1;            /* initially no DRVRs added to UnitTable */
  2715.         printerClassRecord.outRefNum =  -1;    
  2716.         err = LoadResources( &printerClassRecord );
  2717.         if ( err != noErr )
  2718.             USBExpertFatalError( device, err, "\p" kStrPrinterClass "LoadResources failed", 0);
  2719.         //
  2720.         //    routines to write and read to the device must be called by 68K DRVR
  2721.         //        so we use mixed-mode manager to dispatch between PPC and 68K
  2722.         //
  2723.         printerClassRecord.qwrite = (QueueUSBWriteUPP) &printerClassRecord.qwriteRD;
  2724.         printerClassRecord.qwriteRD = qw;
  2725.     
  2726.         printerClassRecord.qread = (QueueUSBReadUPP) &printerClassRecord.qreadRD;
  2727.         printerClassRecord.qreadRD = qr;    
  2728.         
  2729.         printerClassRecord.qstatus = (ControlStatusUPP) &printerClassRecord.qstatusRD;
  2730.         printerClassRecord.qstatusRD = qs;
  2731.  
  2732.         printerClassRecord.qabort = (AbortUPP) &printerClassRecord.qabortRD;
  2733.         printerClassRecord.qabortRD = qa;
  2734.  
  2735.         printerClassRecord.r = (QueueUSBReadUPP) QueueRead;
  2736.         printerClassRecord.w = (QueueUSBWriteUPP) QueueWrite;
  2737.         printerClassRecord.s = (ControlStatusUPP) ControlStatusRequests;
  2738.         printerClassRecord.a = (AbortUPP) Abort;
  2739.  
  2740.         SetNullUSBParamBlock( device, &printerClassRecord.pb );
  2741.         SetNullUSBParamBlock( 0, &printerClassRecord.in );        // fill in pipe ref later
  2742.         SetNullUSBParamBlock( 0, &printerClassRecord.out );    // fill in pipe ref later
  2743.  
  2744. #if DOUBLE_BUFFER
  2745.         //
  2746.         // Assume 1. TRANSFER_SIZE is a power of 2
  2747.         //    Assume 2. malignedBuffer is allocated to be 3*TRANSFER_SIZE
  2748.         //
  2749.         printerClassRecord.pageWriteAlignedBufferSize = TRANSFER_SIZE;                            // should get this from VM
  2750.         printerClassRecord.pageWriteAlignedBuffer = printerClassRecord.malignedBuffer;
  2751.         // align it below the buffer, then bring it into the range of the buffer
  2752.         *((UInt32 *) &printerClassRecord.pageWriteAlignedBuffer) &= ~(printerClassRecord.pageWriteAlignedBufferSize - 1);    //assumption1
  2753.         *((UInt32 *) &printerClassRecord.pageWriteAlignedBuffer) += printerClassRecord.pageWriteAlignedBufferSize;            //assumption2
  2754.  
  2755.         printerClassRecord.pageReadAlignedBufferSize = TRANSFER_SIZE;
  2756.         printerClassRecord.pageReadAlignedBuffer = printerClassRecord.pageWriteAlignedBuffer + TRANSFER_SIZE;
  2757. #endif
  2758.         printerClassRecord.terminating = 0;
  2759.     
  2760.         //
  2761.         //    Just to be thorough, lets hold our paramter blocks so that we won't page them at
  2762.         //        interrupt time. (We should be in the System heap and automatically held.)
  2763.         //
  2764.         HoldMemory( &printerClassRecord, sizeof(struct usbPrinterPBStruct) );
  2765.  
  2766.  
  2767.         //
  2768.         // Start out at first state
  2769.         //
  2770.         printerClassRecord.pb.usbRefcon = kGetConfigurationDescriptor;
  2771.         PrinterDeviceInitiateTransaction(&printerClassRecord.pb);
  2772.     }
  2773. }
  2774.  
  2775. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2776.     Name:        PrintDriverFinalize
  2777.  
  2778.     Input Parameters:    
  2779.         
  2780.     Output Parameters:
  2781.         
  2782.     Description:
  2783.         release any allocated storage
  2784.         remove DRVRs from the UnitTable
  2785.  
  2786.         One small complication happens when the USS-720 cable is used. It's possible
  2787.         that the user has the device plugged in, but the printer wasn't powered on.
  2788.         In this case, our state machine is still cycling between the states 
  2789.         kDelayGetCapability and kGetCapabilityString. If we terminate before the delay
  2790.         returns we'll crash the system. We monitor terminating to handle this
  2791.         
  2792.     Change History:
  2793.         17 Aug 1998,    oja:        don't deregister if the root hub was hot unplugged
  2794.         10 Aug 1998,    oja:        call Abort to cleanup pending read/write transactions
  2795.         31 Jul 1998,    oja:        cleanup some hotplugging problems
  2796.         12 Jul 1998,    oja:        allow for hot unplugging during initial startup
  2797.                                             wait for completion if refCon indicates some
  2798.                                             transaction is in progress
  2799.         24 Apr 1998,    oja:        added call to DeregisterDevice
  2800.         28 Feb 1998,    oja:        Original version.
  2801. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2802. OSStatus
  2803. PrintDriverFinalize( void )
  2804. {
  2805.     OSStatus            result = noErr;
  2806.     unsigned long    tc;
  2807.     //
  2808.     //    notify state machine not to continue
  2809.     //
  2810.     printerClassRecord.terminating = 1;
  2811.     LOGGING( fclose( logfile ) );
  2812.     //
  2813.     //    abort and wait for any pending read/write/status calls
  2814.     //
  2815.     if ( printerClassRecord.pb.usbCompletion != (USBCompletion) NULL )
  2816.     {
  2817.         USBAbortPipeByReference( printerClassRecord.device );
  2818.     }
  2819.     Abort( 0, &printerClassRecord );
  2820.  
  2821.     //    wait for any outstanding startup transactions
  2822.     tc = TickCount() + 10*60;    // wait up to ten seconds
  2823.     while ( TickCount() < tc )
  2824.     {
  2825.         if ( printerClassRecord.pb.usbCompletion == (USBCompletion) NULL
  2826.                 && printerClassRecord.out.usbCompletion == (USBCompletion) NULL 
  2827.                 && printerClassRecord.in.usbCompletion == (USBCompletion) NULL )
  2828.             break;
  2829.     }
  2830.     if ( printerClassRecord.pb.usbCompletion != (USBCompletion) NULL
  2831.             || printerClassRecord.out.usbCompletion != (USBCompletion) NULL 
  2832.             || printerClassRecord.in.usbCompletion != (USBCompletion) NULL )
  2833.         result = (OSStatus) kUSBDeviceBusy;
  2834.  
  2835.     if ( printerClassRecord.pb.usbStatus == noErr )        // don't bother if there was a hot unplug of root hub
  2836.     {
  2837.         //
  2838.         //    remove printer from the name registry
  2839.         //
  2840.         DeregisterDevice( &printerClassRecord );
  2841.     }
  2842.     //
  2843.     //    release any allocated storage
  2844.     //
  2845.     if ( printerClassRecord.capabilityString != printerClassRecord.capability )
  2846.     {
  2847.         MemDeallocatePhysicallyContiguous( printerClassRecord.capabilityString );
  2848.         printerClassRecord.capabilityString = printerClassRecord.capability;
  2849.     }
  2850.  
  2851.     if ( (unsigned char *) printerClassRecord.config != printerClassRecord.configuration )
  2852.     {
  2853.         MemDeallocatePhysicallyContiguous( printerClassRecord.config );
  2854.     }
  2855.     //
  2856.     //    don't need to hang on to param blocks after we've gone away
  2857.     //
  2858.     UnholdMemory( &printerClassRecord, sizeof(struct usbPrinterPBStruct) );
  2859.  
  2860.     return result;
  2861. }
  2862.  
  2863. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2864.     Name:        CFMInitialization
  2865.  
  2866.     Input Parameters:    
  2867.         initBlock
  2868.         
  2869.     Output Parameters:
  2870.         printerClassDriverFileSpec        set global
  2871.         
  2872.     Description:
  2873.         We use the code fragment initialization to get our filespec which 
  2874.         LoadResources will use to open our resource fork.
  2875.         
  2876.         A peculiarity of the USB 1.0 implementation is that does not lock the
  2877.         driver into physical memory. As a result a driver which does not call
  2878.         SetDriverClosureMemory on it's fragment will likely be paged in during
  2879.         interrupt time and a double bus-fault will occur. The solution for this
  2880.         is to have the USB Expert call SetDriverClosureMemory in a future release
  2881.         of the USB stack. In the meantime, we call it on ourselves to lock us into
  2882.         physical memory. When the USB stack is revved, one call to SetDriverClosureMemory
  2883.         (either this one or the Expert's) will be treated as a NOP.
  2884.  
  2885.     Change History:
  2886.         31 Jul 1998,    oja:        added call to SetDriverClosureMemory
  2887.         11 Jun 1998,    oja:        Original version.
  2888. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2889. OSErr
  2890. CFMInitialization( CFragInitBlock *initBlock )
  2891. {
  2892.     //
  2893.     //    get a reference to our file so that we can open up the resource fork later on
  2894.     //
  2895.     if ( CFragHasFileLocation( initBlock->fragLocator.where ) )
  2896.         printerClassDriverFileSpec = *(initBlock->fragLocator.u.onDisk.fileSpec);
  2897.  
  2898.     // don't page us, we're a device driver
  2899.     return SetDriverClosureMemory( (CFragConnectionID) initBlock->closureID, true );
  2900.  
  2901. }
  2902.  
  2903. // eof
  2904.